I would like to merge two Map with JAVA 8 Stream:
Map<String, List<String>> mapGlobal = new HashMap<String, List<String>>();
Map<String, List<String>> mapAdded = new HashMap<String, List<String>>();
I try to use this implementation:
mapGlobal = Stream.of(mapGlobal, mapAdded)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())
));
However, this implementation only create a result like:
Map<String, List<Object>>
If one key is not contained in the mapGlobal
, it would be added as a new key with the corresponding List of String. If the key is duplicated in mapGlobal
and mapAdded
, both list of values will be merge as: A = {1, 3, 5, 7}
and B = {1, 2, 4, 6}
then A ∪ B = {1, 2, 3, 4, 5, 6, 7}
.
Converting only the Value of the Map<Key, Value> into Stream: This can be done with the help of Map. values() method which returns a Set view of the values contained in this map. In Java 8, this returned set can be easily converted into a Stream of key-value pairs using Set. stream() method.
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.
Using foreach over Map can be used to merge given arraylist.
public Map<String, ArrayList<String>> merge(Map<String, ArrayList<String>> map1, Map<String, ArrayList<String>> map2) {
Map<String, ArrayList<String>> map = new HashMap<>();
map.putAll(map1);
map2.forEach((key , value) -> {
//Get the value for key in map.
ArrayList<String> list = map.get(key);
if (list == null) {
map.put(key,value);
}
else {
//Merge two list together
ArrayList<String> mergedValue = new ArrayList<>(value);
mergedValue.addAll(list);
map.put(key , mergedValue);
}
});
return map;
}
You can do this by iterating over all the entries in mapAdded
and merging them into mapGlobal
.
The following iterates over the entries of mapAdded
by calling forEach(action)
where the action consumes the key and value of each entry. For each entry, we call merge(key, value, remappingFunction)
on mapGlobal
: this will either create the entry under the key k
and value v
if the key didn't exist or it will invoke the given remapping function if they already existed. This function takes the 2 lists to merge, which in this case, are first added to a TreeSet
to ensure both unique and sorted elements and converted back into a list:
mapAdded.forEach((k, v) -> mapGlobal.merge(k, v, (v1, v2) -> {
Set<String> set = new TreeSet<>(v1);
set.addAll(v2);
return new ArrayList<>(set);
}));
If you want to run that potentially in parallel, you can create a Stream pipeline by getting the entrySet()
and calling parallelStream()
on it. But then, you need to make sure to use a map that supports concurrency for mapGlobal
, like a ConcurrentHashMap
.
ConcurrentMap<String, List<String>> mapGlobal = new ConcurrentHashMap<>();
// ...
mapAdded.entrySet().parallelStream().forEach(e -> mapGlobal.merge(e.getKey(), e.getValue(), (v1, v2) -> {
Set<String> set = new TreeSet<>(v1);
set.addAll(v2);
return new ArrayList<>(set);
}));
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