2016-06-23 14 views
2

Angenommen, ich habe 3 Autos, jedes Auto hat 3 Motoren, jeder Motor hat 3 Teile. Wie kann ich ein map of <engine_model, List<parts>> daraus mit Java8 Streams erstellen?Wie assemblieren Sie die Map <Key, Value> aus verschachtelten Objekten mit dem Java8-Stream?

In regelmäßigen Java ich folgendes tun würde:

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

hier map ist ein map, dass das Modell des Motors abbildet (type String) zur Liste aller Teile dieses Modells beziehen. verschiedene Autos können dasselbe Motormodell haben.

Ich habe versucht, die folgendes zu tun:

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

das Problem ist, dass über die ich benutze Map<String, List<List<Part>>> bekommen und ich möchte Map<String, List<Part>>

ich eine äquivalente Frage erraten wäre: wie kann ich Ändern Sie die List of Lists in nur List im Zusammenhang mit dem obigen Beispiel?

Antwort

7

Zunächst einmal können Sie sogar Ihre zwingend notwendig Variante vereinfachen:

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

, die wichtig ist, bei der Entscheidung, ob die funktionelle Variante wirklich eine Verbesserung ist. Der flatMap + groupingBy Kollektor ist der richtige Ansatz, aber die Tatsache, dass Sie eine Liste (von Part s) haben, ist ein zusätzliches Hindernis. In Java 9, könnten Sie

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

Aber bis dahin schreiben, müssen wir manuell einen äquivalenten Kollektor montieren:

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 würde ich jetzt mit der Schleife betrachten zu bleiben.

+1

Sie sind ein 'stream()' pro: D –

+0

Danke, @Holger !! Ja, das ist genau das, was ich brauchte, und du hast tatsächlich einige Dinge gelöscht, an denen ich aufgehängt wurde. Ich mache nur meine ersten Babyschritte in die Streams(), aber es fühlt sich sicher wie ein sehr mächtiges Zeug an. – JavaFan

+0

Vorschlagen, die Schleife zu halten ist eigentlich der beste Teil der Antwort. Funktionale Versionen können "cool" sein, sind aber nicht immer eine Verbesserung der Lesbarkeit/Wartbarkeit. – Joffrey