I need to merge n hashmaps ideally in a loop like shown below using java 8 merge or something:
Map 1 : {Name:XXX,Phn:123,Work:""}
Map 2 : {Name:XXX,Phn:456,Work: xyz}
Map 3 : {Name:XXX,Phn:789,Work:""}
I would like to get an output like below :
{
Name:XXX, // if all values for a key are same take one
Phn:123/456/789 // merge all non null values for same key
Work:xyz // make sure non-null values are never replaced
}
When I try to use putall like this
public Map<String,String> mergeOriginalDataMaps(List<Integer> indexList, List<Map<String,String>> originalData) {
Map<String,String> tmpMap = new HashMap<String,String> ();
for (int index : indexList ) {
tmpMap.putAll(originalData.get(index));
}
return tmpMap;
}
If the value of duplicate key is ""
, the previous value is replaced with the new one. I need to concatenate the values rather than replace them.
We can also use the putAll() method to merge two hashmaps. However, if a key is present in both hashmaps, the old value is replaced by the new value. Unlike the merge() , the putAll() method does not provide the remapping function. Hence, we cannot decide what value to store for duplicate keys.
Assuming that both maps contain the same set of keys, and that you want to "combine" the values, the thing you would be looking for is a Pair class, see here for example. You simply iterate one of the maps; and retrieve values from both maps; and create a Pair; and push that in your result map.
The merge(Key, Value, BiFunctional) method of HashMap class is used to combine multiple mapped values for a key using the given mapping function.
Alternatively, we can use Stream#concat() function to merge the maps together. This function can combine two different streams into one. As shown in the snippet, we are passed the streams of map1 and map2 to the concate() function and then collected the stream of their combined entry elements.
If you have a List<Map<String, String>>
, which represents a list of maps to merge, you can have
Map<String, String> result =
maps.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(
Map.Entry::getValue,
Collectors.collectingAndThen(Collectors.<String>toSet(), s -> String.join("", s))
)
));
This flat maps each map into a Stream of its entries. Then the Stream is grouped by the value of each entry and all distinct elements with the same key are mapped to their value, joined.
The distinct part is made possible by first collecting all the values inside a Set
.
Sample code:
public static void main(String[] args) {
List<Map<String, String>> maps = new ArrayList<>();
maps.add(new HashMap<String, String>(){{ put("Name", "XXX"); put("Phn", "123"); put("Work", ""); }});
maps.add(new HashMap<String, String>(){{ put("Name", "XXX"); put("Phn", "456"); put("Work", "xyz"); }});
maps.add(new HashMap<String, String>(){{ put("Name", "XXX"); put("Phn", "789"); put("Work", ""); }});
Map<String, String> result =
maps.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(
Map.Entry::getValue,
Collectors.collectingAndThen(Collectors.<String>toSet(), s -> String.join("", s))
)
));
System.out.println(result); // prints "{Phn=123456789, Work=xyz, Name=XXX}"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With