Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grouping by List of Map in Java 8

I have a List like this:

List<Map<String, Long>>

Is there a way, using lambda, to convert this list to:

Map<String, List<Long>>

Example:

Map<String, Long> m1 = new HashMap<>();
m1.put("A", 1);
m1.put("B", 100);

Map<String, Long> m2 = new HashMap<>();
m2.put("A", 10);
m2.put("B", 20);
m2.put("C", 100);

List<Map<String, Long>> beforeFormatting = new ArrayList<>();
beforeFormatting.add(m1);
beforeFormatting.add(m2);

After formatting:

Map<String, List<Long>> afterFormatting;

which would look like:

A -> [1, 10]
B -> [100, 20]
C -> [100]
like image 240
test123 Avatar asked Dec 09 '15 08:12

test123


People also ask

How to group list in Java 8?

In Java 8, you retrieve the stream from the list and use a Collector to group them in one line of code. It's as simple as passing the grouping condition to the collector and it is complete. By simply modifying the grouping condition, you can create multiple groups.

What is grouping by in Java 8?

The groupingBy() method of Collectors class in Java are used for grouping objects by some property and storing results in a Map instance. In order to use it, we always need to specify a property by which the grouping would be performed. This method provides similar functionality to SQL's GROUP BY clause.

What does Collectors groupingBy do?

groupingBy. Returns a Collector implementing a cascaded "group by" operation on input elements of type T , grouping elements according to a classification function, and then performing a reduction operation on the values associated with a given key using the specified downstream Collector .

What is a flatMap in Java 8?

In Java 8 Streams, the flatMap() method applies operation as a mapper function and provides a stream of element values. It means that in each iteration of each element the map() method creates a separate new stream. By using the flattening mechanism, it merges all streams into a single resultant stream.


1 Answers

You need to flatMap the entry set of each Map to create a Stream<Map.Entry<String, Long>>. Then, this Stream can be collected with the groupingBy(classifier, downstream) collector: the classifier returns the key of the entry and the downstream collector maps the entry to its value and collects that into a List.

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

This code needs the following static imports:

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;

With your full example:

public static void main(String[] args) {
    Map<String, Long> m1 = new HashMap<>();
    m1.put("A", 1l);
    m1.put("B", 100l);

    Map<String, Long> m2 = new HashMap<>();
    m2.put("A", 10l);
    m2.put("B", 20l);
    m2.put("C", 100l);

    List<Map<String, Long>> beforeFormatting = new ArrayList<>();
    beforeFormatting.add(m1);
    beforeFormatting.add(m2);

    Map<String, List<Long>> afterFormatting =
        beforeFormatting.stream()
                        .flatMap(m -> m.entrySet().stream())
                        .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));

    System.out.println(afterFormatting); // prints {A=[1, 10], B=[100, 20], C=[100]}
}
like image 184
Tunaki Avatar answered Sep 20 '22 11:09

Tunaki