Reputation: 2030
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 = ???
Upvotes: 14
Views: 13045
Reputation: 246
Same Same But Different
Map<String, Set<String>> m = new HashMap<>();
as.forEach(a -> {
m.computeIfAbsent(a.name, v -> new HashSet<>())
.add(a.property);
});
Upvotes: 3
Reputation: 15294
@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
Upvotes: 7
Reputation: 13855
Also, you can use the merger function option of the Collectors.toMap function Collectors.toMap(keyMapper,valueMapper,mergeFunction) as follows:
final Map<String, String> m = as.stream()
.collect(Collectors.toMap(
x -> x.name,
x -> x.property,
(property1, property2) -> property1+";"+property2);
Upvotes: 0
Reputation: 794
groupingBy does exactly what you want:
import static java.util.stream.Collectors.*;
...
as.stream().collect(groupingBy((x) -> x.name, mapping((x) -> x.property, toSet())));
Upvotes: 30