您如何使用 Java8 流从嵌套对象 assemble 映射 <Key, Value>?
How do you assemble Map<Key, Value> from nested objects using Java8 stream?
假设我有 3 辆车,每辆车有 3 个引擎,每个引擎有 3 个零件。如何使用 Java8 流从中创建 map of <engine_model, List<parts>>
?
在常规情况下 java 我会执行以下操作:
Map<String, List<Parts>> map = new HashMap<String, List<Parts>>();
for (Car car: cars){
for (Engine engine: car.getEngines()){
if (!map.contains(engine.getModel())){
map.put(engine.getModel(), new ArrayList<Part>());
}
for (Part part: engine.getParts()){
map.get(engine.getModel()).add(part);
}
}
}
此处 map
是一个 map
,它将引擎的模型 (type String
) 映射到属于该模型的所有零件的列表。不同的汽车可以有相同的发动机型号。
我尝试执行以下操作:
carList.stream().flatMap(p -> p.getEngines().stream())
.collect(Collectors.groupingBy(p -> p.getModel(),
Collectors.mapping(Engine::getParts, Collectors.toList())))
问题是使用上面我得到
Map<String, List<List<Part>>>
而且我要
Map<String, List<Part>>
我想一个等价的问题是:如何将上例中的 List of Lists
更改为 List
?
首先,您甚至可以简化命令式变体:
Map<String, List<Part>> map = new HashMap<>();
for(Car car: cars) {
for(Engine engine: car.getEngines()) {
map.computeIfAbsent(engine.getModel(), key -> new ArrayList<>())
.addAll(engine.getParts());
}
}
在决定功能变体是否真的是改进时,这一点很重要。 flatMap
+ groupingBy
收集器是正确的方法,但是您有一个列表(Part
的列表)要展平是一个额外的障碍。在 Java 9 中,您可以写
Map<String, List<Part>> map = cars.stream()
.flatMap(car -> car.getEngines().stream())
.collect(Collectors.groupingBy(Engine::getModel,
Collectors.flatMapping(e -> e.getParts().stream(), Collectors.toList())));
但在那之前,我们必须手动 assemble 一个等效的收集器:
Map<String, List<Part>> map = cars.stream()
.flatMap(car -> car.getEngines().stream())
.collect(Collectors.groupingBy(Engine::getModel,
Collector.of(ArrayList::new, (l,e) -> l.addAll(e.getParts()),
(l1,l2) -> { l1.addAll(l2); return l1; })));
所以我会考虑暂时留在循环中。
假设我有 3 辆车,每辆车有 3 个引擎,每个引擎有 3 个零件。如何使用 Java8 流从中创建 map of <engine_model, List<parts>>
?
在常规情况下 java 我会执行以下操作:
Map<String, List<Parts>> map = new HashMap<String, List<Parts>>();
for (Car car: cars){
for (Engine engine: car.getEngines()){
if (!map.contains(engine.getModel())){
map.put(engine.getModel(), new ArrayList<Part>());
}
for (Part part: engine.getParts()){
map.get(engine.getModel()).add(part);
}
}
}
此处 map
是一个 map
,它将引擎的模型 (type String
) 映射到属于该模型的所有零件的列表。不同的汽车可以有相同的发动机型号。
我尝试执行以下操作:
carList.stream().flatMap(p -> p.getEngines().stream())
.collect(Collectors.groupingBy(p -> p.getModel(),
Collectors.mapping(Engine::getParts, Collectors.toList())))
问题是使用上面我得到
Map<String, List<List<Part>>>
而且我要
Map<String, List<Part>>
我想一个等价的问题是:如何将上例中的 List of Lists
更改为 List
?
首先,您甚至可以简化命令式变体:
Map<String, List<Part>> map = new HashMap<>();
for(Car car: cars) {
for(Engine engine: car.getEngines()) {
map.computeIfAbsent(engine.getModel(), key -> new ArrayList<>())
.addAll(engine.getParts());
}
}
在决定功能变体是否真的是改进时,这一点很重要。 flatMap
+ groupingBy
收集器是正确的方法,但是您有一个列表(Part
的列表)要展平是一个额外的障碍。在 Java 9 中,您可以写
Map<String, List<Part>> map = cars.stream()
.flatMap(car -> car.getEngines().stream())
.collect(Collectors.groupingBy(Engine::getModel,
Collectors.flatMapping(e -> e.getParts().stream(), Collectors.toList())));
但在那之前,我们必须手动 assemble 一个等效的收集器:
Map<String, List<Part>> map = cars.stream()
.flatMap(car -> car.getEngines().stream())
.collect(Collectors.groupingBy(Engine::getModel,
Collector.of(ArrayList::new, (l,e) -> l.addAll(e.getParts()),
(l1,l2) -> { l1.addAll(l2); return l1; })));
所以我会考虑暂时留在循环中。