2016-01-11 9 views
11

Ich habe Map<A, Map<B, C>> und ich möchte Map<B, List<C>> davon mit Java-Streams bekommen.Java Streams: Werte durch inneren Kartenschlüssel gruppiert

ich versuche, es zu tun, wie folgt:

public <A, B, C> Map<B, List<C>> groupsByInnerKey(Map<A, Map<B, C>> input) { 
    return input.values() 
      .stream() 
      .flatMap(it -> it.entrySet().stream()) 
      .collect(Collectors.groupingBy(Map.Entry::getKey)); 
} 

Was ich erwarte:

  • flatMap eine Funktion Stream von Map.Entry<B, C>
  • collect(Collectors.groupingBy(...)) nimmt gibt, die Map.Entry<B, C> angewendet wird, und kehrt B, somit sammelt es Werte von C in List<C>.

Aber es nicht kompiliert, wörtlich:

Nicht statische Methode kann nicht von einem statischen Kontext referenziert wird

bei Map.Entry::getKey in der letzten Zeile.

Kann jemand erklären, was falsch ist oder was ist der richtige Weg, um das zu erreichen, was ich will?

+0

Mögliche doppelte: http://stackoverflow.com/questions/29373026/how-to-get-all-values-from-the-inner-maps-of-a-map-using-a-common -Schlüssel –

+0

@ShiladittyaChakraborty, nicht wirklich, ich frage, warum die erwartete Art, dies zu tun, nicht funktioniert. Außerdem unterscheidet sich die Aufgabe etwas von der Frage, auf die Sie verwiesen haben. – hotkey

Antwort

11

Ihr Stream ist zusammengesetzt aus Map.Entry Objekte, sondern wollen Sie sammeln möchten ist eigentlich der Wert des Eintrags , nicht der Eintrag selbst. Mit Ihrem aktuellen Code erhalten Sie eine Map<B, List<Map.Entry<B, C>>>.

Als solche verpassen Sie nur einen Anruf an Collectors.mapping. Dieser Collector bildet das Stream-Element mit der angegebenen Mapper-Funktion ab und sammelt dieses Ergebnis im Downstream-Container. In diesem Fall lautet der Mapper Map.Entry::getValue (der Wert wird also vom Karteneintrag zurückgegeben), und der nachgeordnete Kollektor sammelt sich in List.

public <A, B, C> Map<B, List<C>> groupsByInnerKey(Map<A, Map<B, C>> input) { 
    return input.values() 
      .stream() 
      .flatMap(it -> it.entrySet().stream()) 
      .collect(Collectors.groupingBy(
       Map.Entry::getKey, 
       Collectors.mapping(Map.Entry::getValue, Collectors.toList()) 
      )); 
} 
+1

Danke, es hat funktioniert. Also, ich war tatsächlich verwirrt durch die Fehlermeldung des Compilers. Es sollte über nicht übereinstimmende Typen und nicht über nicht statischen Kontext gesagt werden. :) – hotkey

7

Ihre Stream-Pipeline gibt eine Map<B, List<Map.Entry<B,C>>> zurück, keine Map<B, List<C>>.

Zu bekommen, was ein Map<B, List<C>>, benötigen Sie einen mapping hinzufügen, die Map.Entry<B,C>-C Karte würde:

return input.entrySet() 
     .stream() 
     .flatMap(it -> it.getValue().entrySet().stream()) 
     .collect(Collectors.groupingBy(Map.Entry::getKey,Collectors.mapping(Map.Entry::getValue,Collectors.toList())));