Ich habe eine Liste von employees
. Sie haben isActive
Boolesches Feld. Ich möchte teilen employees
in zwei Listen: activeEmployees
und formerEmployees
. Ist es möglich, die Stream-API zu verwenden? Was ist der raffinierteste Weg?
Java Stream: durch boolesches Prädikat in zwei Listen teilen
Andy Turner
Map<Boolean, List<Employee>> partitioned =
listOfEmployees.stream().collect(
Collectors.partitioningBy(Employee::isActive));
Die resultierende Karte enthält zwei Listen, die dem entsprechen, ob das Prädikat gefunden wurde oder nicht:
List<Employee> activeEmployees = partitioned.get(true);
List<Employee> formerEmployees = partitioned.get(false);
Es gibt ein paar Gründe für die Verwendung partitioningBy
über groupingBy
(wie von Juan Carlos Mendoza vorgeschlagen):
Erstens der Parameter von groupingBy
ist ein Function<Employee, Boolean>
(in diesem Fall), und so besteht die Möglichkeit, ihm eine Funktion zu übergeben, die null zurückgeben kann, was bedeutet, dass es eine dritte Partition geben würde, wenn diese Funktion für einen der Mitarbeiter null zurückgibt. was zu einem führen würde partitioningBy
verwendet a Predicate<Employee>
sodass immer nur 2 Partitionen zurückgegeben werden können.NullPointerException
wird vom Kollektor ausgelöst: Obwohl nicht explizit dokumentiert, wird explizit eine Ausnahme für Nullschlüssel ausgelöst, vermutlich aufgrund des Verhaltens von Map.computeIfAbsent
dass “wenn die Funktion null zurückgibt, keine Zuordnung aufgezeichnet wird”, was bedeutet, dass Elemente sonst stillschweigend aus der Ausgabe gelöscht würden. (Danke an lczapski für den Hinweis).
Zweitens erhalten Sie zwei Listen partitioningBy
in der resultierenden Karte mit groupingBy
; mit
System.out.println(
Stream.empty().collect(Collectors.partitioningBy(a -> false)));
// Output: {false=[], true=[]}
System.out.println(
Stream.empty().collect(Collectors.groupingBy(a -> false)));
// Output: {}
erhalten Sie nur Schlüssel/Wert-Paare, bei denen Elemente dem angegebenen Schlüssel zugeordnet sind: Dieses Verhalten ist in der nicht dokumentiert Java 8 Javadocaber es wurde für hinzugefügt
-
Java 9
.
und drittens ist die Karte, die Sie erhalten, intern optimiert, um nur zwei Tasten zu halten.
-
– Eugen
Stream.of(1,2,3,4).collect(groupingBy(x -> x == 3 ? null : x >= 3))
19. September 2018 um 7:00 Uhrjava.lang.NullPointerException: element cannot be mapped to a null key
Ich war neugierig darauf: “Übergeben einer Funktion, die null zurückgeben kann, was bedeutet, dass es eine dritte Partition geben würde, wenn diese Funktion null zurückgibt”. Ich habe einen Code erstellt, der null zurückgibtund nach der Ausführung wurde eine Ausnahme zurückgegeben:
. Es kann also nicht wahr sein.
-
– lczapski 9. September 2019 um 7:25 Uhr@lczapski interessant, ich werde die Antwort aktualisieren. Das ist eigentlich nicht
dokumentiert
obwohl.
-
– Andy Turner
Map.computeIfAbsent
9. September 2019 um 8:52 Uhr@lczapski Ich denke, diese Einschränkung kommt implizit von
die besagt, dass “Wenn die Funktion null zurückgibt, keine Zuordnung aufgezeichnet wird”.
– Andy Turner 9. September 2019 um 8:58 Uhr Sie können auch verwenden
Map<Boolean, List<Employee>> grouped = employees.stream()
.collect(Collectors.groupingBy(Employee::isActive));
List<Employee> activeEmployees = grouped.get(true);
List<Employee> formerEmployees = grouped.get(false);
-
GruppierungNach in diesem Fall gibt es 2 Gruppenmöglichkeiten (aktive und inaktive Mitarbeiter): +1, aber beachten Sie, dass Sie es sein sollten
groupingBy
leichtFunction<Employee, Boolean>
vorsichtig mit diesem Ansatz: der Parameter vonnull
ist einpartitioningBy
und so besteht die Möglichkeit, ihm eine Funktion zu übergeben, die zurückkehren kannPredicate
, was bedeutet, dass es eine dritte Partition geben würde, wenn diese Funktion für einen der Mitarbeiter null zurückgibt. Dieverwendet a
sodass immer nur 2 Partitionen zurückgegeben werden können.
-
– Andy Turner
groupingBy
26. Oktober 2017 um 15:34 UhrIch habe nur ein wenig experimentiert und festgestellt, dass es andere Gründe gibt, es nicht zu verwenden
– Schauen Sie sich die Bearbeitung meiner Antwort an. (Entschuldigung, ich versuche definitiv nicht nur, Ihre Antwort zu zerreißen, ich habe tatsächlich etwas gelernt, indem ich die beiden ausprobiert habe!)
-
– Andy Turner
isActive
26. Oktober 2017 um 15:41 Uhr@AndyTurner danke. Für diesen Fall gehe ich davon aus
wird nicht null zurückgeben (wie es einen primitiven booleschen Wert verwendet).
-
– Juan Carlos Mendoza 26. Oktober 2017 um 15:48 Uhr Ich würde auch davon ausgehen, dass es so ist. Ich weise nur darauf hin, dass es das gibt
groupingBy
Wahrscheinlichkeitüber
.
– Andy Turner
26. Oktober 2017 um 15:53 Uhr
Adrian Collectors::teeing
List<List<Employee>> divided = employees.stream().collect(
Collectors.teeing(
Collectors.filtering(Employee::isActive, Collectors.toList()),
Collectors.filtering(Predicate.not(Employee::isActive), Collectors.toList()),
List::of
));
System.out.println(divided.get(0)); //active
System.out.println(divided.get(1)); //inactive
Was ist der raffinierteste Weg?
Java 12 natürlich mit neu Collectors2.partition
Donald Rab Wenn Sie bereit sind, eine Bibliothek eines Drittanbieters zu verwenden, funktioniert dies mitvon
PartitionMutableList<Employee> partition =
employees.stream().collect(
Collectors2.partition(Employee::isActive, PartitionFastList::new));
List<Employee> activeEmployees = partition.getSelected();
List<Employee> formerEmployees = partition.getRejected();
Eclipse-Sammlungen ListIterate
.
PartitionMutableList<Employee> partition =
ListIterate.partition(employees, Employee::isActive);
List<Employee> activeEmployees = partition.getSelected();
List<Employee> formerEmployees = partition.getRejected();
PartitionMutableList
Sie können die Dinge auch vereinfachen, indem Sie verwenden PartitionIterable
. PartitionIterable
ist ein Typ, der sich erstreckt von getSelected()
. Jede Unterart von getRejected()
hat eine Sammlung für positive Ergebnisse
und negative Ergebnisse
Mögliches Duplikat von How to partition a list by predicate using java8?
– Malte Hartwig
26. Oktober 2017 um 15:47 Uhr
@MalteHartwig beachte dieses Duplikat sagt “Prädikat”, aber OP fragt tatsächlich nach der Gruppierung nach einer Funktion. Ich würde jedoch nicht wieder öffnen, wenn es so geschlossen wäre.
– Andy Turner
26. Oktober 2017 um 15:54 Uhr