Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Stream Collectors.toMap value is a Set

I want to use a Java Stream to run over a List of POJOs, such as the list List<A> below, and transform it into a Map Map<String, Set<String>>.

For example, class A is:

class A {
    public String name;
    public String property;
}

I wrote the code below that collects the values into a map Map<String, String>:

final List<A> as = new ArrayList<>();
// the list as is populated ...

// works if there are no duplicates for name
final Map<String, String> m = as.stream().collect(Collectors.toMap(x -> x.name, x -> x.property));

However, because there might be multiple POJOs with the same name, I want the value of the map be a Set. All property Strings for the same key name should go into the same set.

How can this be done?

// how do i create a stream such that all properties of the same name get into a set under the key name
final Map<String, Set<String>> m = ???
like image 489
tkja Avatar asked Oct 05 '16 19:10

tkja


People also ask

How does Collector toMap work?

The toMap() method is a static method of Collectors class which returns a Collector that accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements.

What is Merge function in collectors toMap?

Collectors.toMap() with Mapper and Merge Functions It's input are two values that is the two values for which keyMapper returned the same key, and merges those two values into a single one.

What does collect collectors toList ()) do?

Collectors toList() method in Java with Examples It returns a Collector Interface that gathers the input data onto a new list. This method never guarantees type, mutability, serializability, or thread-safety of the returned list but for more control toCollection(Supplier) method can be used.

How do I collect a stream map?

Method 1: Using Collectors.toMap() Function The Collectors. toMap() method takes two parameters as the input: KeyMapper: This function is used for extracting keys of the Map from stream value. ValueMapper: This function used for extracting the values of the map for the given key.


2 Answers

groupingBy does exactly what you want:

import static java.util.stream.Collectors.*;
...
as.stream().collect(groupingBy((x) -> x.name, mapping((x) -> x.property, toSet())));
like image 175
Nevay Avatar answered Oct 15 '22 16:10

Nevay


@Nevay 's answer is definitely the right way to go by using groupingBy, but it is also achievable by toMap by adding a mergeFunction as the third parameter:

as.stream().collect(Collectors.toMap(x -> x.name, 
    x -> new HashSet<>(Arrays.asList(x.property)), 
    (x,y)->{x.addAll(y);return x;} ));

This code maps the array to a Map with a key as x.name and a value as HashSet with one value as x.property. When there is duplicate key/value, the third parameter merger function is then called to merge the two HashSet.

PS. If you use Apache Common library, you can also use their SetUtils::union as the merger

like image 21
SwiftMango Avatar answered Oct 15 '22 15:10

SwiftMango