Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to merge a collection of Maps using streams

I have a collection of maps:

Collection<Map<String,Double>> myCol = table.values();

I would like to transform this into a Map

Map<String, Double>

such that, for a matching key, values are summed up. Using a for loop, it is rather simple:

Map<String, Double> outMap = new HashMap<>();
for (Map<String, Double> map : myCol) {
    outMap =  mergeMaps(outMap, map);
}

and mergeMaps() is defined as

mergeMaps(Map<String, Double> m1, Map<String, Double> m2){    
    Map<String, Double> outMap = new TreeMap<>(m1);
    m2.forEach((k,v) -> outMap.merge(k,v,Double::sum)); /*sum values if key exists*/
    return outMap;
}

However, I would like to use streams to get a map from collection. I have tried as follows:

Map<String, Double> outMap = new HashMap<>();    
myCol.stream().forEach(e-> outMap.putAll(mergeMaps(outMap,e)));
return outMap;

This works without a problem. However, can I still improve it? I mean, how can I use collectors in it?

like image 642
novice Avatar asked Nov 16 '17 16:11

novice


People also ask

Can you combine two maps?

If Google recognizes both locations' addresses, create a joint map by entering both addresses into Google Maps' text boxes. Alternatively, find the locations manually on separate pages, then merge them onto a single map.

What does the merge () method on map do?

The Java HashMap merge() method inserts the specified key/value mapping to the hashmap if the specified key is already not present. If the specified key is already associated with a value, the method replaces the old value with the result of the specified function.

Which stream is used to merge multiple streams?

The concat() method is a static method of the Stream Interface that can be used to merge two streams into a single stream. The merged stream contains all the elements of the first stream, followed by all the elements of the second stream. If both the streams are ordered, then the merged stream will be ordered.


1 Answers

From your input, you can fetch the stream of maps and then flatmap it to have a Stream<Map.Entry<String, Double>>. From there, you collect them into a new map, specifying that you want to sum the values mapped to the same key.

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingDouble;
import static java.util.stream.Collectors.toMap;

....

Map<String, Double> outMap = 
    myCol.stream()
         .flatMap(m -> m.entrySet().stream())
         .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, Double::sum));

Alternatively, you can use groupingBy instead of toMap:

.collect(groupingBy(Map.Entry::getKey, summingDouble(Map.Entry::getValue)));
like image 164
Alexis C. Avatar answered Oct 29 '22 17:10

Alexis C.