I have something like the below :
public class MyClass {
private Long stackId
private Long questionId
}
A collection of say 100, where the
The straight-forward way with the Stream API involves 2 Stream pipelines:
Map>
of stackId
to questionIds
. This is done with the groupingBy(classifier, downstream) collectors where we classify per the stackId
and values having the same stackId
are mapped to their questionId
(with mapping) and collected into a list with toList().MyOtherClass
instance and collects that into a list.Assuming you have a constructor MyOtherClass(Long stackId, Collection
, a sample code would be:
Map> map =
list.stream()
.collect(Collectors.groupingBy(
MyClass::getStackId,
Collectors.mapping(MyClass::getQuestionId, Collectors.toList())
));
List result =
map.entrySet()
.stream()
.map(e -> new MyOtherClass(e.getKey(), e.getValue()))
.collect(Collectors.toList());
Using StreamEx library, you could do that in a single Stream pipeline. This library offers a pairing and first collectors. This enables to pair two collectors and perform a finisher operation on the two collected results:
stackId
of the grouped elements (they will all be the same, by construction)questionId
and collecting into a list.MyOtherClass
.Sample code:
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import static one.util.streamex.MoreCollectors.first;
import static one.util.streamex.MoreCollectors.pairing;
// ...
Collection result =
StreamEx.of(list)
.groupingBy(
MyClass::getStackId,
pairing(
collectingAndThen(mapping(MyClass::getStackId, first()), Optional::get),
mapping(MyClass::getQuestionId, toList()),
MyOtherClass::new
)
).values();