Say I have a List of Pair objects,
List<Pair<A,B>> listOfPairs = //some list of pairs ;
I would like to group this list into a Map<A,Set<B>>
.
Currently, I can do this in two steps. The first step groups by A, and returns a
Map<A,Set<Pair<A,B>>
as follows:
Map<A,Set<Pair<A,B>> intermediateStep = listOfPairs.stream().collect(Collectors.groupingBy((Pair::getLeft), Collectors.toSet()));
I then stream the entryset of the map above and collect them into the desired end result, mainly by mapping each Pair object to its B value, and collecting them to a set:
Map<A, Set<B>> finalResult= intermediateStep.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().stream().map(Pair::getRight).collect(Collectors.toSet())));
Is there a better way to achieve the desired result, perhaps in one step? In other words, the intermediate step mentioned above groups by A, but the right side of the grouping returns the entire Pair object. I'd like to group by A and point A to the set of its associated Bs in one step.
(I know that just because I could do it in one step, doesn't mean I should, because readability might suffer, but I'm curious.)
Thanks!
You can simplify the code by passing a mapping
collector into the groupingBy
collector like this:
Map<A, Set<B>> collect =
listOfPairs.stream()
.collect(Collectors.groupingBy(Pair::getLeft,
Collectors.mapping(Pair::getRight,
Collectors.toSet())));
You can do it using Map.computeIfAbsent
:
Map<A, Set<B>> finalResult = new HashMap<>();
listOfPairs.forEach(pair -> finalResult.computeIfAbsent(
pair.getLeft(),
k -> new HashSet<>())
.add(pair.getRight()));
If you want to preserve insertion order you can use LinkedHashMap
and LinkedHashSet
instead of HashMap
and HashSet
, respectively.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With