Wenn ich eine habe List<List<Object>>
, wie kann ich daraus eine machen List<Object>
, die alle Objekte in derselben Iterationsreihenfolge enthält, indem ich die Funktionen von Java 8 verwende?
Wenn ich eine habe List<List<Object>>
, wie kann ich daraus eine machen List<Object>
, die alle Objekte in derselben Iterationsreihenfolge enthält, indem ich die Funktionen von Java 8 verwende?
Antworten:
Sie können flatMap
die internen Listen (nachdem Sie sie in Streams konvertiert haben) in einen einzelnen Stream reduzieren und das Ergebnis dann in einer Liste zusammenfassen:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
Class::method
fühlt sich anfangs etwas komisch an, hat aber den Vorteil, dass es deklariert, von welcher Art von Objekt Sie ein Mapping durchführen. Das ist etwas, was Sie sonst in Streams verlieren.
Die flatMap
Methode on Stream
kann diese Listen sicherlich für Sie reduzieren, muss jedoch Stream
Objekte für das Element und dann a Stream
für das Ergebnis erstellen .
Sie brauchen nicht alle diese Stream
Objekte. Hier ist der einfache, präzise Code zur Ausführung der Aufgabe.
// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);
Da a List
is ist Iterable
, ruft dieser Code die forEach
Methode (Java 8-Funktion) auf, von der geerbt wird Iterable
.
Führt die angegebene Aktion für jedes Element von aus,
Iterable
bis alle Elemente verarbeitet wurden oder die Aktion eine Ausnahme auslöst. Aktionen werden in der Reihenfolge der Iteration ausgeführt, wenn diese Reihenfolge angegeben ist.
Und a List
's Iterator
gibt Artikel in sequentieller Reihenfolge zurück.
Für den Consumer
Code wird eine Methodenreferenz (Java 8-Funktion) an die Methode vor Java 8 übergeben List.addAll
, um die inneren Listenelemente nacheinander hinzuzufügen.
Hängt alle Elemente in der angegebenen Sammlung an das Ende dieser Liste in der Reihenfolge an, in der sie vom Iterator der angegebenen Sammlung zurückgegeben werden (optionale Operation).
Sie können das flatCollect()
Muster aus Eclipse-Sammlungen verwenden .
MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);
Wenn Sie die Liste nicht ändern können von List
:
List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);
Hinweis: Ich bin ein Mitarbeiter von Eclipse Collections.
Genau wie @Saravana erwähnt hat:
Flatmap ist besser, aber es gibt andere Möglichkeiten, dasselbe zu erreichen
listStream.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});
Zusammenfassend gibt es verschiedene Möglichkeiten, um dasselbe zu erreichen:
private <T> List<T> mergeOne(Stream<List<T>> listStream) {
return listStream.flatMap(List::stream).collect(toList());
}
private <T> List<T> mergeTwo(Stream<List<T>> listStream) {
List<T> result = new ArrayList<>();
listStream.forEach(result::addAll);
return result;
}
private <T> List<T> mergeThree(Stream<List<T>> listStream) {
return listStream.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});
}
private <T> List<T> mergeFour(Stream<List<T>> listStream) {
return listStream.reduce((l1, l2) -> {
List<T> l = new ArrayList<>(l1);
l.addAll(l2);
return l;
}).orElse(new ArrayList<>());
}
private <T> List<T> mergeFive(Stream<List<T>> listStream) {
return listStream.collect(ArrayList::new, List::addAll, List::addAll);
}
Ich möchte nur ein weiteres Szenario wie erklären List<Documents>
, diese Liste enthält einige weitere Listen anderer Dokumente wie List<Excel>
, List<Word>
, List<PowerPoint>
. Die Struktur ist also
class A {
List<Documents> documentList;
}
class Documents {
List<Excel> excels;
List<Word> words;
List<PowerPoint> ppt;
}
Wenn Sie Excel nur aus Dokumenten iterieren möchten, gehen Sie wie folgt vor.
Der Code wäre also
List<Documents> documentList = new A().getDocumentList();
//check documentList as not null
Optional<Excel> excelOptional = documentList.stream()
.map(doc -> doc.getExcel())
.flatMap(List::stream).findFirst();
if(excelOptional.isPresent()){
Excel exl = optionalExcel.get();
// now get the value what you want.
}
Ich hoffe, dies kann jemandes Problem beim Codieren lösen ...
Wir können hierfür Flatmap verwenden, siehe folgenden Code:
List<Integer> i1= Arrays.asList(1, 2, 3, 4);
List<Integer> i2= Arrays.asList(5, 6, 7, 8);
List<List<Integer>> ii= Arrays.asList(i1, i2);
System.out.println("List<List<Integer>>"+ii);
List<Integer> flat=ii.stream().flatMap(l-> l.stream()).collect(Collectors.toList());
System.out.println("Flattened to List<Integer>"+flat);
Eine Erweiterung von Erans Antwort, die die beste Antwort war. Wenn Sie mehrere Listenebenen haben, können Sie diese weiterhin flach abbilden.
Dies bietet auch eine praktische Möglichkeit zum Filtern, wenn Sie bei Bedarf auch die Ebenen herunterfahren.
Also zum Beispiel:
List<List<List<List<List<List<Object>>>>>> multiLayeredList = ...
List<Object> objectList = multiLayeredList
.stream()
.flatmap(someList1 -> someList1
.stream()
.filter(...Optional...))
.flatmap(someList2 -> someList2
.stream()
.filter(...Optional...))
.flatmap(someList3 -> someList3
.stream()
.filter(...Optional...))
...
.collect(Collectors.toList())
Dies ähnelt in SQL SELECT-Anweisungen in SELECT-Anweisungen.
Methode zum Konvertieren von a List<List>
in List
:
listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
Siehe dieses Beispiel:
public class Example {
public static void main(String[] args) {
List<List<String>> listOfLists = Collections.singletonList(Arrays.asList("a", "b", "v"));
List<String> list = listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
System.out.println("listOfLists => " + listOfLists);
System.out.println("list => " + list);
}
}
Es druckt:
listOfLists => [[a, b, c]]
list => [a, b, c]
::
:)