Multiple key map and partial query - java

I search map implementation with multiple key. I know Apache Commons but it dosen't satisfy me.
I want to be able to pass one key and get all entries which contain the passed key, e.g.
MultiKeyMap mkm = new MultiKeyMap();
mkm.put("key1", "key2", "key3", "1");
mkm.put("key1", "key22", "key33", "2");
mkm.put("key12", "key22", "key32", "3");
mkm.get("key1");
returns null but in this case I want to get "1" and "2"
My own implementation is not an option. I want to use something which I can trust.

I think Guava has a Table implementation Table<Key1,Key2,Value> where you can do table.get(key1) or table.get(key2) or table.get(key1, key2). I think it only supports two keys per table, but not sure. Might want to take a look at that.
Guava Table javadoc

I think you can do this with HashMap
HashMap<String, ArrayList<String>> map = new HashMap<>();
ArrayList<String> ls=new ArrayList<>();
ArrayList<String> ls2=new ArrayList<>();
ls.add("key3");
ls.add("1");
ls.add("key2");
ls.add("key22");
ls.add("key33");
ls.add("2");
ls2.add("key22");
ls2.add("key32");
ls2.add("3");
map.put("key1",ls);
map.put("key12", ls2);
map.get("key1");

If you can turn the requirement around and put the value multiple times, once for each key, then Guava's MultiMap is very nice to use:
Multimap<String, String> map = HashMultimap.create();
map.put("key1", "1");
map.put("key2", "1");
map.put("key3", "1");
map.put("key1", "2");
map.put("key22", "2");
map.put("key33", "2");
map.put("key12", "3");
map.put("key22", "3");
map.put("key32", "3");
Collection<String> values = map.get("key1");
System.out.println(values);
prints
[2, 1]

Related

How to seperate a list of map of strings according to a key value in the list map?

I have a list of Map of Strings like this
List<Map<String, String>> dataListMap = new ArrayList<>();
Map<String, String> dataMap = new HashMap<String, String>() {
{
put("Charged fare", "3");
put("Trip ID", "1");
put("Account", "220");
}
};
dataListMap.add(dataMap);
dataMap = new HashMap<String, String>() {
{
put("Charged fare", "5");
put("Trip ID", "2");
put("Account", "220");
}
};
dataListMap.add(dataMap);
dataMap = new HashMap<String, String>() {
{
put("Charged fare", "7");
put("Trip ID", "3");
put("Account", "230");
}
};
dataListMap.add(dataMap);
dataMap = new HashMap<String, String>() {
{
put("Charged fare", "8");
put("Trip ID", "4");
put("Account", "230");
}
};
dataListMap.add(dataMap);
I want to separate this list by the account number and convert this to two list in side a List<List<Map<String,String>>> Is there an easy way to do that?Please help
List<List<Map<String, String>>> groupedByIds =
new ArrayList<>(dataListMap.stream()
.collect(Collectors.groupingBy(i -> i.get("Account")))
.values());
System.out.println(groupedByIds);
I believe that this is what you asked for but you should try specifying your use case, it can probably be better designed.
Collection<List<Map<String, String>>> accountString = dataListMap.stream().collect(groupingBy(m -> m.get("Account"))).values(); for(List<Map<String, String>> account: accountString){ calculateDailyCap(account); } is it possible to convert this back to only one list?
List<Map<String,String>> regroupedList = groupedByIds.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(regroupedList);
Yes you can do it with flatmap, but you already have the list at the start why would you do that?
Stream never affects the result of your initial Collection, it always returns new result, so it is safe to reuse the list you had at the start.
I think you need to iterate over the list and push the Maps in two new Lists of Maps according to their Account number.
However without knowing the precise task you're trying to achieve, I would consider creating a new class that holds the three attributes you currently contain in your map.
That would result it way more robust code, that is also easier to extend in the future.

Compare two Maps and remove all the elements that either have the same key or the same value

I have two Maps that I need to compare and merge them into a result map. I need to remove all the elements that either have the same key or the same value.
Basically, say I have two Maps:
Map<String, String> map1 = new HashMap<>();
map1.put("1", "A");
map1.put("2", "A");
map1.put("3", "B");
map1.put("4", "C");
map1.put("5", "D");
map1.put("6", "E");
Map<String, String> map2 = new HashMap<>();
map2.put("1", "B");
map2.put("2", "A");
map2.put("4", "F");
map2.put("6", "C");
map2.put("7", "G");
map2.put("8", "H");
I need to remove all the entries that have either the same keys or the same values and need to retain back only bidirectional unique entries. So after merge, I need to have the following result map in which every key maps to a unique value and every value has a unique key:
("5", "D"), ("7", "G"), ("8", "H")
What's the best way to do this in Java?
I would create another map that contains all the values and keys from map1 and map2, and then I would go through a loop deleting the duplicates keys and values
Map<String, String> map3 = new HashMap<>();
map3.putAll(map1);
map3.putAll(map2);
for(String a: map1.keySet()){
if(map2.containsKey(a) || map2.containsValue(map1.get(a))){
map3.remove(a);
}
}
Hope this is useful!
Below code will do this
Map map3 = new HashMap<>(map1);
map3.keySet().removeAll(map2.keySet());
map3.values().removeAll(map2.values());
map2.keySet().removeAll(map1.keySet());
map2.values().removeAll(map1.values());
map3.putAll(map2);
System.out.println(map3);
This will result {7=G, 5=D, 8=H}
Interesting problem. I can't think of a particularly neat way of doing it but here's a potential solution using Java 8 - I'm pretty sure it could be simplified somewhat. I don't like these sorts of stateful operations mid stream but the only way I can see to avoid it is to split it into two operations.
Set<Map.Entry<String, String>> values = new HashSet<>();
Map<String,String> mergedMap =
Stream.concat(map1.entrySet().stream(), map2.entrySet().stream)
.filter(e -> !values.keySet().contains(e.getKey()))
.filter(e -> !values.valueSet().contains(e.getValue()))
.peek(e -> values.add(e))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Best design/coding to accomplish the below requirement?

I am using Java 1.7. I have below map.
Map<String, String> keyValues = new HashMap<>();
But map can contain values as below.
keyValues.put("one", "value1");
keyValues.put("two", "value2");
OR
keyValues.put("four", "value1");
keyValues.put("two", "value2");
keyValues.put("seven", "value3");
OR
keyValues.put("one", "value1");
keyValues.put("two", "value2");
keyValues.put("three", "value3");
Basically the map can contain N values where is N is generic it can contain any number of values.
I have one more value for group of keys as below.
keys one, two belongs to 12345SRT
keys one, two, three, four belongs to 12345SRTSSS
keys four, two, seven belongs to 764RTYL87
Now map can contain any one of above key sets.
In that case based on the key set in the map it has to return corresponding value.
Ex:
If map contains one and two then it should return 12345SRT.
If map contains four,two and seven then logic should return 764RTYL87.
What is the best place to keep above key sets and corresponding values?
Shall i consider enum?
The logic has to take map and return value.
What is the best way to do that?
You can use Apache MultiKeyMap
Example
MultiKeyMap multiKeyMap = new MultiKeyMap();
multiKeyMap.put("New York","IBM","Sam");
multiKeyMap.put("Sydney","Infosys","Honey");
multiKeyMap.put("Prague","JP Morgan","Peter");
multiKeyMap.put("Scotland","RBS","Deny");
multiKeyMap.put("Paris","Nomura","Lily");
multiKeyMap.put("Melbourne","Citi Bank","Sandy");
multiKeyMap.put("Aukland","Bank of America","Tommy");
Resultant map
Similar question: How to implement a Map with multiple keys?
EDIT :
You can have a custom key class which can have N number of keys.
Something like
Class MyKey{
List<String> keys;
}
Map<MyKey, String> keyValues = new HashMap<>();
Also override appropriate methods of Map like equals,hashcode,get etc.
Maybe this?
HashMap<Set<String>, String> multiMap = new HashMap<Set<String>, String>();
Set<String> mk1 = new HashSet<String>();
mk1.add("one");
mk1.add("two");
mk1.add("three");
multiMap.put(mk1, "derp");
Set<String> checker = new HashSet<String>();
checker.add("two");
checker.add("three");
checker.add("one");
if(multiMap.containsKey(checker))
System.out.println(multiMap.get(checker));
Try running this and see if it's the behavior you're wanting.
You can use as below :
Map<String, ArrayList<String>> keyValues = new HashMap<String, ArrayList<String>();
keyValues.put("12345SRT",["one","two"]);
keyValues.put("12345SRTSSS",["one", "two", "three", "four"]);
keyValues.put("764RTYL87",["four", "two", "seven"]);
Ex:if you have a map object with keys as "one" and "two"
String getKey(map){
for (Map.Entry<String, Object> e : keyValues.entrySet()) {
String key = e.getKey();
ArrayList<string> value = e.getValue();
if(value.containsAll(map.keySet())){
return key;
}
}
}

java. is there any google's guava interface to replace Map<String, Map<String, String>>?

for example, the code are like this, it is a little complicated, how can i use google's guava lib in this context and clean my code?
#Test
public void testMap2() {
Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
addToMap(map, "cib", "1004", "2");
addToMap(map, "cib", "1005", "3");
addToMap(map, "cib", "1006", "1");
addToMap(map, "cib", "1007", "5");
addToMap(map, "icbc", "1004", "2");
addToMap(map, "icbc", "1005", "3");
addToMap(map, "icbc", "1006", "1");
addToMap(map, "icbc", "1007", "5");
System.out.println(map);
}
private void addToMap(Map<String, Map<String, String>> map, String key, String name, String value) {
if(map.containsKey(key)) {
map.get(key).put(name, value);
} else {
Map<String, String> map1 = new HashMap<String, String>();
map1.put(name, value);
map.put(key, map1);
}
}
Yes, it's called Table:
A collection that associates an ordered pair of keys, called a row key
and a column key, with a single value. A table may be sparse, with
only a small fraction of row key / column key pairs possessing a
corresponding value.
The mappings corresponding to a given row key may
be viewed as a Map whose keys are the columns. The reverse is also
available, associating a column with a row key / value map. Note that,
in some implementations, data access by column key may have fewer
supported operations or worse performance than data access by row key.
There are few implementations:
ArrayTable (backed by two-dimentional array, see the documentation),
ForwardingTable (implements decorator pattern),
HashBasedTable (~ HashMap<R, HashMap<C, V>),
ImmutableTable (immutable and null-hostile),
TreeBasedTable (~ TreeMap<R, TreeMap<C, V>)
Also see the Wiki explaining Guava new collection types, specifically code example:
Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);
weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5
which demonstrates clean way to achieve what you want.
P.S. Guava Wiki is your friend!

Creating Hashmap using existing hashmap

I created a hashmap as shown below:
Map<String, String> streetno = new HashMap<String, String>();
streetno.put("3", "Sachin");
streetno.put("2", "Dravid");
streetno.put("1", "Sehwag");
streetno.put("5", "Laxman");
streetno.put("4", "Kohli");
Now I want to create a new hashmap where key of the above hashmap becomes value and value becomes key as shown below:
Map<String, String> streetname = new HashMap<String, String>();
streetname.put("Sachin", "3");
streetname.put("Dravid", "2");
streetname.put("Sehwag", "1");
streetname.put("Laxman", "5");
streetname.put("Kohli", "4");
I don't know how to do that.. Can anyone help me out with this..
Map<String, String> streetname = new HashMap<String, String>();
for (Entry<String,String> e : streetno.entrySet()) {
streetname.put(e.getValue(), e.getKey());
}
Here, the for loop iterates over all entries (i.e. key/value pairs) in the original map, and inserts them into the second map with the key and value swapped over.
It is probably a good idea to check that put() returns null. If you get a non-null value, this means that the values in streetno are not unique. Since this is homework, I leave it to you to figure out the consequences, and how best to handle this.
Perfect you are almost there. Now you need to iterate the first hash map keys and simulate what you have done in those 5 lines:
streetname.put("Sachin", "3");
streetname.put("Dravid", "2");
streetname.put("Sehwag", "1");
streetname.put("Laxman", "5");
streetname.put("Kohli", "4");
Tip: iteration over map might be a bit tricky for you, but usually it is done like that:
for (String key : streetno.keySet()) {
...
}
Good luck with your homework!
Java 8:
Map<String, String> streetname =
streetno.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
Note:
If you are tempted to use parellelstream() instead of stream() think twice about it. This would only be appropriate if your Map is extremely large.

Categories