Map values in Collectors.groupingBy()
I found a solution; It involves Collections.mapping()
, which can wrap a collector and apply mapping function over stream to supply elements to the wrapped collector:
static <T, U> Map<T, Set<U>> groupSecondByFirst(Collection<Tuple<T, U>> tuples) {
return tuples
.stream()
.collect(
Collectors.groupingBy(
Tuple::getFirst,
Collectors.mapping(
Tuple::getSecond,
Collectors.toSet())));
}
Comments
-
Feuermurmel almost 2 years
For the sake of this example, let's assume I have a simple type
Tuple
with two attributes:interface Tuple<T, U> { T getFirst(); U getSecond(); }
Now I want to transform a collection of
(first, second)
tuples into a map which maps eachfirst
value to a set of allsecond
values contained in tuples with that specificfirst
value. The methodgroupSecondByFirst()
shows a possible implementation doing what I want:<T, U> Map<T, Set<U>> groupSecondByFirst(Set<Tuple<T, U>> tuples) { Map<T, Set<U>> result = new HashMap<>(); for (Tuple<T, U> i : tuples) { result.computeIfAbsent(i.getFirst(), x -> new HashSet<>()).add(i.getSecond()); } return result; }
If the input was
[(1, "one"), (1, "eins"), (1, "uno"), (2, "two"), (3, "three")]
the output would be{ 1 = ["one", "eins", "uno"], 2 = ["two"], 3 = ["three"] }
I would like to know whether and how I can implement this using the streams framework. The best I got is the following expression, which returns a map which contains the full tuple as values and not just their
second
elements:Map<T, Set<Tuple<T, U>>> collect = tuples.stream().collect( Collectors.groupingBy(Tuple::getFirst, Collectors.toSet()));