【发布时间】:2019-01-18 12:29:25
【问题描述】:
假设我有一组碰碰车,它们的侧面有尺寸、颜色和标识符(“汽车代码”)。
class BumperCar {
int size;
String color;
String carCode;
}
现在我需要将碰碰车映射到DistGroup 对象中的List,每个对象都包含size、color 和List 的汽车代码属性。
class DistGroup {
int size;
Color color;
List<String> carCodes;
void addCarCodes(List<String> carCodes) {
this.carCodes.addAll(carCodes);
}
}
例如,
[
BumperCar(size=3, color=yellow, carCode=Q4M),
BumperCar(size=3, color=yellow, carCode=T5A),
BumperCar(size=3, color=red, carCode=6NR)
]
应该导致:
[
DistGroup(size=3, color=yellow, carCodes=[ Q4M, T5A ]),
DistGroup(size=3, color=red, carCodes=[ 6NR ])
]
我尝试了以下方法,它实际上做了我想要它做的事情。但问题是它实现了中间结果(变成Map),我也认为它可以立即完成(也许使用mapping或collectingAndThen或reducing或其他东西),从而更优雅代码。
List<BumperCar> bumperCars = …;
Map<SizeColorCombination, List<BumperCar>> map = bumperCars.stream()
.collect(groupingBy(t -> new SizeColorCombination(t.getSize(), t.getColor())));
List<DistGroup> distGroups = map.entrySet().stream()
.map(t -> {
DistGroup d = new DistGroup(t.getKey().getSize(), t.getKey().getColor());
d.addCarCodes(t.getValue().stream()
.map(BumperCar::getCarCode)
.collect(toList()));
return d;
})
.collect(toList());
如何在不使用中间结果的变量的情况下获得所需的结果?
编辑:如何在不实现中间结果的情况下获得所需的结果?我只是在寻找一种不会实现中间结果的方法,至少表面上不会。这意味着我不喜欢使用这样的东西:
something.stream()
.collect(…) // Materializing
.stream()
.collect(…); // Materializing second time
当然,如果可能的话。
请注意,为简洁起见,我省略了 getter 和构造函数。您还可以假设 equals 和 hashCode 方法已正确实现。另请注意,我使用的是SizeColorCombination,我将其用作分组键。这个类显然包含属性size 和color。也可以使用 Tuple、Pair、Entry 等类或表示两个任意值组合的任何其他类。
编辑:另请注意,ol' skool for 循环当然可以使用,但这不在这个问题的范围内。
【问题讨论】:
-
顺便说一句,
groupingBy()默认情况下会将值分组为List,因此可以省略toList() -
使用流的想法是使代码更具可读性、更不言自明(以性能为代价)或无需样板代码即可大规模并行化。这不是旧方法的现代万能解决方案。您提供的代码充其量是神秘的。我建议使用经典的 for 循环,在这种情况下更简洁。
-
@Lino 你是对的。我删除了它。
-
@MarkJeronimus 没错,这就是为什么我对当前的解决方案不满意并寻找一种优雅的方式来实现相同的结果——如果它存在的话。否则我会很乐意回到经典循环。
标签: java java-8 java-stream grouping collectors