Ich habe einen Datensatz, der durch einen Java 8-Stream dargestellt wird:
Stream<T> stream = ...;
Ich kann sehen, wie man es filtert, um eine zufällige Teilmenge zu erhalten - zum Beispiel
Random r = new Random();
PrimitiveIterator.OfInt coin = r.ints(0, 2).iterator();
Stream<T> heads = stream.filter((x) -> (coin.nextInt() == 0));
Ich kann auch sehen, wie ich diesen Stream reduzieren kann, um beispielsweise zwei Listen zu erhalten, die zwei zufällige Hälften des Datensatzes darstellen, und diese dann wieder in Streams umzuwandeln. Aber gibt es eine direkte Möglichkeit, zwei Streams aus dem ersten zu generieren? Etwas wie
(heads, tails) = stream.[some kind of split based on filter]
Vielen Dank für jeden Einblick.
java
java-8
java-stream
user1148758
quelle
quelle
Stream
in mehrereStream
s zu konvertieren , obwohl ich denke, dass Leute, die diese Frage erreicht haben, tatsächlich nach dem Weg suchen, dies zu erreichen, unabhängig von einer solchen Einschränkung, die Marks Antwort ist. Dies kann daran liegen, dass die Frage im Titel nicht mit der in der Beschreibung übereinstimmt .Antworten:
Nicht genau. Sie können nicht zwei
Stream
aus einem herausholen; Das macht keinen Sinn - wie würden Sie über eines iterieren, ohne das andere gleichzeitig generieren zu müssen? Ein Stream kann nur einmal bearbeitet werden.Wenn Sie sie jedoch in eine Liste oder etwas anderes kopieren möchten, können Sie dies tun
quelle
stream.collect(...)
for mit vordefinierten thread-sicheren Sammlungen, dieCollectors
auch bei nicht thread-sicheren Sammlungen (ohne synchronisierte Sperrenkonflikte) gut funktionieren. Beste Antwort von @MarkJeronimus.Hierfür kann ein Kollektor verwendet werden.
Collectors.partitioningBy()
Factory.Dadurch wird ein
Map
VonBoolean
bis erstelltList
und Elemente basierend auf a in die eine oder andere Liste eingefügtPredicate
.Hinweis: Da der Stream als Ganzes verbraucht werden muss, kann dies bei unendlichen Streams nicht funktionieren. Und weil der Stream sowieso verbraucht wird, werden sie bei dieser Methode einfach in Listen eingefügt, anstatt einen neuen Stream mit Speicher zu erstellen. Sie können diese Listen jederzeit streamen, wenn Sie Streams als Ausgabe benötigen.
Außerdem ist der Iterator nicht erforderlich, auch nicht in dem von Ihnen bereitgestellten Nur-Kopf-Beispiel.
Collectors.groupingBy()
Factory.Falls die Streams nicht sind
Stream
, aber einer der primitiven Streams wieIntStream
, dann ist diese.collect(Collectors)
Methode nicht verfügbar. Sie müssen dies manuell ohne Sammlerfabrik tun. Die Implementierung sieht folgendermaßen aus:[Beispiel 2.0 seit 2020-04-16]
In diesem Beispiel initialisiere ich die ArrayLists mit der vollen Größe der ursprünglichen Sammlung (falls dies überhaupt bekannt ist). Dies verhindert Größenänderungsereignisse auch im schlimmsten Fall, kann jedoch möglicherweise 2 * N * T-Speicherplatz verschlingen (N = anfängliche Anzahl von Elementen, T = Anzahl von Threads). Um den Platz gegen die Geschwindigkeit auszutauschen, können Sie ihn weglassen oder Ihre am besten fundierte Vermutung verwenden, z. B. die erwartete höchste Anzahl von Elementen in einer Partition (normalerweise etwas mehr als N / 2 für eine ausgeglichene Aufteilung).
Ich hoffe, ich beleidige niemanden mit einer Java 9-Methode. Informationen zur Java 8-Version finden Sie im Bearbeitungsverlauf.
quelle
stream.boxed().collect(...);
! Es wird wie angekündigt funktionieren: Konvertieren Sie das GrundelementIntStream
in die Box-Stream<Integer>
Version.(map, x) -> { boolean partition = p.test(x); List<Integer> list = map.get(partition); list.add(x); }
können Sie einfach verwenden(map, x) -> map.get(p.test(x)).add(x)
. Außerdem sehe ich keinen Grund, warum dercollect
Vorgang nicht threadsicher sein sollte. Es funktioniert genau so, wie es funktionieren soll und sehr genau so, wieCollectors.partitioningBy(p)
es funktionieren würde. Aber ich würde einIntPredicate
statt verwenden,Predicate<Integer>
wenn ich es nicht benutzeboxed()
, um zweimaliges Boxen zu vermeiden.Ich bin über diese Frage gestolpert und habe das Gefühl, dass ein gegabelter Stream einige Anwendungsfälle hat, die sich als gültig erweisen könnten. Ich habe den folgenden Code als Verbraucher geschrieben, damit er nichts tut, aber Sie können ihn auf Funktionen und alles andere anwenden, auf das Sie stoßen könnten.
Jetzt könnte Ihre Code-Implementierung ungefähr so aussehen:
quelle
Leider ist das, wonach Sie fragen, im JavaDoc von Stream direkt verpönt :
Sie können dies mit
peek
oder mit anderen Methoden umgehen, wenn Sie diese Art von Verhalten wirklich wünschen. In diesem Fall sollten Sie nicht versuchen, zwei Streams von derselben ursprünglichen Stream-Quelle mit einem Gabelfilter zu sichern, sondern Ihren Stream duplizieren und jedes der Duplikate entsprechend filtern.Möglicherweise möchten Sie jedoch erneut prüfen, ob a
Stream
die geeignete Struktur für Ihren Anwendungsfall ist.quelle
List<Stream> forkStream(Stream s)
aber meine resultierenden Streams werden zumindest teilweise von Sammlungen und nicht direkt vom zugrunde liegenden Stream unterstützt, im Gegensatz dazu,filter
was keine Terminal-Stream-Operation ist.Dies ist gegen den allgemeinen Mechanismus von Stream. Angenommen, Sie können Stream S0 wie gewünscht in Sa und Sb aufteilen. Wenn Sie beispielsweise eine Terminaloperation
count()
an Sa ausführen, werden alle Elemente in S0 "verbraucht". Daher hat Sb seine Datenquelle verloren.Zuvor hatte Stream eine
tee()
Methode, die einen Stream in zwei dupliziert. Es ist jetzt entfernt.Stream verfügt jedoch über eine peek () -Methode, mit der Sie möglicherweise Ihre Anforderungen erfüllen können.
quelle
peek
ist genau das, was früher wartee
.nicht genau, aber Sie können möglicherweise erreichen, was Sie benötigen, indem Sie aufrufen
Collectors.groupingBy()
. Sie erstellen eine neue Sammlung und können dann Streams für diese neue Sammlung instanziieren.quelle
Dies war die am wenigsten schlechte Antwort, die ich finden konnte.
Dies nimmt einen Strom von ganzen Zahlen und teilt sie bei 5 auf. Bei mehr als 5 werden nur gerade Zahlen gefiltert und in eine Liste aufgenommen. Für den Rest verbindet es sie mit |.
Ausgänge:
Es ist nicht ideal, da es alles in Zwischensammlungen sammelt, die den Strom brechen (und zu viele Argumente hat!).
quelle
Ich bin auf diese Frage gestoßen, als ich nach einer Möglichkeit gesucht habe, bestimmte Elemente aus einem Stream herauszufiltern und als Fehler zu protokollieren. Ich musste den Stream also nicht wirklich aufteilen, sondern einem Prädikat mit unauffälliger Syntax eine vorzeitige Beendigungsaktion hinzufügen. Folgendes habe ich mir ausgedacht:
quelle
Kürzere Version, die Lombok verwendet
quelle
Wie wäre es mit:
quelle