简体   繁体   English

你如何组装地图 <Key, Value> 从使用Java8流的嵌套对象?

[英]How do you assemble Map<Key, Value> from nested objects using Java8 stream?

Suppose I have 3 cars, each car having 3 engines, each engine having 3 parts. 假设我有3辆汽车,每辆汽车有3个发动机,每个发动机有3个零件。 How can I create a map of <engine_model, List<parts>> out of this using Java8 streams? 如何使用Java8流创建map of <engine_model, List<parts>>的映射?

In regular java I would do the following: 在常规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);
    }
  }
}

here map is a map that maps the engine's model ( type String ) to the list of all the parts pertaining to that model. 这里map是一个map ,它将引擎的模型( type String )映射到与该模型相关的所有部分的列表。 different cars can have same engine model. 不同的车可以有相同的发动机型号。

I tried to do the following: 我试着做以下事情:

carList.stream().flatMap(p -> p.getEngines().stream())
  .collect(Collectors.groupingBy(p -> p.getModel(),
               Collectors.mapping(Engine::getParts, Collectors.toList())))

the problem is that using above I am getting Map<String, List<List<Part>>> and I want Map<String, List<Part>> 问题是上面使用我得到Map<String, List<List<Part>>>我想要Map<String, List<Part>>

I guess an equivalent question would be: how do I change the List of Lists to just List in the context of the above example? 我想一个等价的问题是:如何在上面的例子的上下文中将List of Lists更改为仅List

First of all, you can even simplify your imperative variant: 首先,您甚至可以简化您的命令式变体:

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());
    }
}

That's important when deciding whether the functional variant is really an improvement. 在决定功能变体是否真的是一种改进时,这一点很重要。 The flatMap + groupingBy collector is the right approach, but the fact that you have a list (of Part s) to flatten is an additional obstacle. flatMap + groupingBy收集器是正确的方法,但是你有一个( Part s)列表的事实是一个额外的障碍。 In Java 9, you could write 在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())));

But until then, we have to manually assemble an equivalent collector: 但在那之前,我们必须手动组装一个等效的收集器:

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; })));

So I would consider staying with the loop for now. 所以我现在考虑继续使用循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM