How to groupBy object properties and map to another object using Java 8 Streams?
Solution-1
Just merging the two steps into one:
List<DistGroup> distGroups = bumperCars.stream()
.collect(Collectors.groupingBy(t -> new SizeColorCombination(t.getSize(), t.getColor())))
.entrySet().stream()
.map(t -> {
DistGroup d = new DistGroup(t.getKey().getSize(), t.getKey().getColor());
d.addCarCodes(t.getValue().stream().map(BumperCar::getCarCode).collect(Collectors.toList()));
return d;
})
.collect(Collectors.toList());
Solution-2
Your intermediate variable would be much better if you could use groupingBy
twice using both the attributes and map the values as List
of codes, something like:
Map<Integer, Map<String, List<String>>> sizeGroupedData = bumperCars.stream()
.collect(Collectors.groupingBy(BumperCar::getSize,
Collectors.groupingBy(BumperCar::getColor,
Collectors.mapping(BumperCar::getCarCode, Collectors.toList()))));
and simply use forEach
to add to the final list as:
List<DistGroup> distGroups = new ArrayList<>();
sizeGroupedData.forEach((size, colorGrouped) ->
colorGrouped.forEach((color, carCodes) -> distGroups.add(new DistGroup(size, color, carCodes))));
Note: I've updated your constructor such that it accepts the card codes list.
DistGroup(int size, String color, List<String> carCodes) {
this.size = size;
this.color = color;
addCarCodes(carCodes);
}
Further combining the second solution into one complete statement(though I would myself favor the forEach
honestly):
List<DistGroup> distGroups = bumperCars.stream()
.collect(Collectors.groupingBy(BumperCar::getSize,
Collectors.groupingBy(BumperCar::getColor,
Collectors.mapping(BumperCar::getCarCode, Collectors.toList()))))
.entrySet()
.stream()
.flatMap(a -> a.getValue().entrySet()
.stream().map(b -> new DistGroup(a.getKey(), b.getKey(), b.getValue())))
.collect(Collectors.toList());
If we assume that DistGroup
has hashCode/equals
based on size
and color
, you could do it like this:
bumperCars
.stream()
.map(x -> {
List<String> list = new ArrayList<>();
list.add(x.getCarCode());
return new SimpleEntry<>(x, list);
})
.map(x -> new DistGroup(x.getKey().getSize(), x.getKey().getColor(), x.getValue()))
.collect(Collectors.toMap(
Function.identity(),
Function.identity(),
(left, right) -> {
left.getCarCodes().addAll(right.getCarCodes());
return left;
}))
.values(); // Collection<DistGroup>