2016-06-22 11 views
1

ich dachte, dass ich in Java 8 Streams ziemlich gut bekommen, aber dann ...Java Stream sammeln mit mehreren Schlüsseln abzubilden

Ich habe eine Foo Schnittstelle:

public interface Foo { 
    String getKey(); 
    Stream<Bar> bars(); 
} 

Ich weiß, ich sammeln ein Stream<Foo> in eine Map<String, Foo> den Schlüssel jedes mit:

Map<String, Foo> foosByKey = fooStream.collect(
    Collectors.toMap(Foo::getKey, Function.identity())); 

Aber was, wenn ich sie in eine Map<Bar, Foo> sammeln möchten? Mit anderen Worten, für jede Foo in der Dampf, möchte ich setzen, dass Foo in der Karte auf jede der Bar Instanzen zurückgegeben von Foo.bars() zurückgegeben. Wo soll ich anfangen?

+0

Nein, Sie haben es rückwärts. Eine "Map " würde eine Eins-zu-Eins-Zuordnung zwischen "Bar" - und "Foo" -Instanzen implizieren. Betrachten Sie 'Map ' oder 'Map ', wo eine Person mehrere Kreditkarten haben kann und ein Buch mehrere ISBNs haben kann. Nichts kompliziert hier. –

+0

Ich verstehe die Bedeutung, aber ich wollte nicht auf Punkte, die ein wenig Nebensache sind, hängen. Ob eine Zuordnung bidirektional ist, hängt davon ab, ob der Graph richtungsabhängig ist. Eine Java Map ist unidirektional, so dass Sie nicht zurückmelden können. Deshalb hat Guava beispielsweise eine BiMap. Ich glaube, du wolltest sagen, dass die Beziehung eins zu eins ist - in diesem Fall ist die Beziehung viel-zu-eins ('Bar'-'Foo'). Aber wieder ist das alles nebensächlich - Dinge, die man bei einem Bier diskutieren kann. Die Zusammenfassung ist, dass jedes "Foo" viele "Bar" haben kann, und ich "Bar" auf "Foo" abbilden möchte. Prost! –

+0

Tatsächlich können wir mit der Aussage schließen, dass jedes 'Foo' viele' Bar' haben kann und dass alle 'Bar's verschieden sind und, nun, ich denke [Sotirios 'Antwort] (http://stackoverflow.com/a/37956805/2711488) enthält eine geeignete Lösung. Gibt es irgendetwas, das dich davon abhält, seine Antwort zu akzeptieren, die wir ansprechen sollten? – Holger

Antwort

2

Wie vorgeschlagen here, Sie wollen die Bar Werte von jedem Foo extrahieren und Paare von ihnen erstellen. Sobald Sie die Paare haben, können Sie sie in eine Map sammeln. Zum Beispiel

Map<Bar, Foo> map = fooStream.flatMap(foo -> foo.bars().map(bar -> new SimpleEntry<>(bar, foo))) 
      .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); 

Wir verwenden SimpleEntry hier, weil es verfügbar ist (Java ist kein einfacher Pair Typ haben). Sie könnten Ihre eigenen schreiben, um genauer zu sein.

+1

Der 'SimpleEntry <>' Gebrauch ist cool --- Ich hatte nicht bemerkt, dass Java etwas hatte, das mindestens einem 'Paar' ähnlich war. Insgesamt habe ich auf etwas kompakteres gehofft, aber das ist vielleicht das Beste, was wir bekommen können. Ich werde es noch eine Weile lassen, um zu sehen, ob wir noch andere Möglichkeiten haben. –

+1

Java 9 wird die Möglichkeit hinzufügen, 'Map.entry (bar, foo)' 'zu verwenden, um wertbasierte, unveränderbare Einträge in einer prägnanteren Art zu konstruieren. – Holger

Verwandte Themen