I'm learning java 8 stream now, I'm curious is there any convenient way to convert List<Pair<A,B>>
to List<Pair<A,List<B>>>
, which is to merge values of pair by key?
I ever thought to use forEach
method, but it seems less efficient since I need to traverse the new list to check the key of pair.
I would suggest using a LinkedHashMap
(which also supports the insertion order of the entries) instead of List<Pair<>>
. Using that you can simply use Collectors.groupingBy()
and Collectors.mapping()
to achieve that:
List<Pair<A, B>> list = ...;
Map<A, List<B>> result = list.stream()
.collect(Collectors.groupingBy(Pair::getKey, LinkedHashMap::new,
Collectors.mapping(Pair::getValue, Collectors.toList())));
However if you really need a List<Pair<>>
you can transform the map back to this:
List<Pair<A, B>> list = ...;
List<Pair<A, List<B>>> result = list.stream()
.collect(Collectors.groupingBy(Pair::getKey, LinkedHashMap::new,
Collectors.mapping(Pair::getValue, Collectors.toList())))
.entrySet().stream()
.map(e -> new Pair<>(e.getKey(), e.getValue()))
.collect(Collectors.toList());
Bare in mind that you iterate twice with this solution (first the list, second the map).
Beside that, if you also want to remove duplicates of B
you can use a LinkedHashSet
(which also keeps the order) for that. For this you just need to change the mapping downstream collector:
List<Pair<A, B>> list = ...;
Map<A, Set<B>> result = list.stream()
.collect(Collectors.groupingBy(Pair::getKey, LinkedHashMap::new,
Collectors.mapping(Pair::getValue, Collectors.toCollection(LinkedHashSet::new))));