Java 8 stream aggregate a map

java, java-8, java-stream, lambda

Solution

I'll assume that you're starting with a stream of maps:

Stream<Map<String, Sometype>> input = ... ;

You got pretty far with the flatmapping and collecting. However, the code you tried,

    input.flatMap(map -> map.entrySet().stream())
         .collect(Collectors.groupingBy(Map.Entry::getKey));

gives you a map whose keys are `String` and whose values are a list of map entries, specifically `List<Map.Entry<String,Sometype>>`, not a `List<Sometype>` as you wanted. What you have to do is use the "downstream" feature of collectors after you've grouped them by key. You want to take each `Map.Entry` and extract (map) it to its value, which is `Sometype`. This is done with a `mapping` collector.

Now you potentially have several instances of `Sometype` for each key, so you need to collect them into a list. This is done using another downstream collector, which collects them into a list. This is done using the familiar `toList()` collector.

The final code looks like this:

Map<String, List<Sometype>> result =
    input.flatMap(map -> map.entrySet().stream())
         .collect(groupingBy(Map.Entry::getKey,
                             mapping(Map.Entry::getValue,
                                     toList())));

Problem

Im trying to do something seemingly straighforward but with no luck so far. I have a list of Map, they come from a bunch of CompletableFutures in parallel, the result then has to be joined. Since the key in the map is unique, In need to merge the values and produce a new map of unique keys associated with the combined list of SomeType. For example: Map1: key1 : Sometype1 key2 : Sometype2 Map2 key1 : Sometype3 key2 : Sometype4 Desired final result: Map3: key1 : Sometype, Sometype3 key2 : Sometype2, Sometype4 I tried using groupBy and other methods, but it seems most of them assume working with a List and not a Map to begin with so I wasn't able to find a straightforward way to do it. So far I have something like: ``` Map<String, List<Sometype>> volPercent = waitGroup.stream() .map(CompletableFuture::join) .flatMap((e) -> e.entrySet().stream()) .collect(Collectors.groupingBy()); ``` The part I'm not sure is what needs to go in the grouping by part. I tried Map.Entry::getKey, but it doesn't compile: ``` Error:(69, 25) java: incompatible types: inference variable T has incompatible bounds equality constraints: com.Sometype lower bounds: java.util.Map.Entry<java.lang.String,com.Sometype> ```

Original source