Se ho un List<List<Object>>, come posso trasformarlo in un List<Object>che contiene tutti gli oggetti nello stesso ordine di iterazione usando le funzionalità di Java 8?
Se ho un List<List<Object>>, come posso trasformarlo in un List<Object>che contiene tutti gli oggetti nello stesso ordine di iterazione usando le funzionalità di Java 8?
Risposte:
È possibile utilizzare flatMapper appiattire gli elenchi interni (dopo averli convertiti in stream) in un singolo stream, quindi raccogliere il risultato in un elenco:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
Class::methodall'inizio sembra un po 'strano, ma ha il vantaggio di dichiarare da che tipo di oggetto stai mappando. Questo è qualcosa che altrimenti perdi nei flussi.
Il flatMapmetodo su Streampuò certamente appiattire quegli elenchi per te, ma deve creare Streamoggetti per elemento, quindi aStream per il risultato.
Non hai bisogno di tutti quegli Streamoggetti. Ecco il codice semplice e conciso per eseguire l'attività.
// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);
Perché a Listè Iterable, questo codice chiama il forEachmetodo (funzionalità Java 8), che è ereditato da Iterable.
Esegue l'azione specificata per ciascun elemento
Iterablefino a quando tutti gli elementi non sono stati elaborati o l'azione genera un'eccezione. Le azioni vengono eseguite nell'ordine di iterazione, se tale ordine è specificato.
E un List's Iteratorrestituisce gli elementi in ordine sequenziale.
Per Consumerquesto, questo codice passa un riferimento di metodo (funzionalità Java 8) al metodo pre-Java 8 List.addAllper aggiungere in sequenza gli elementi dell'elenco interno.
Aggiunge tutti gli elementi nella raccolta specificata alla fine di questo elenco, nell'ordine in cui vengono restituiti dall'iteratore della raccolta specificata (operazione facoltativa).
È possibile utilizzare il flatCollect()modello da Collezioni Eclipse .
MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);
Se non puoi cambiare la lista da List:
List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);
Nota: sono un collaboratore delle raccolte Eclipse.
Proprio come ha detto @Saravana:
flatmap è migliore ma ci sono altri modi per ottenere lo stesso
listStream.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});
Per riassumere, ci sono diversi modi per ottenere lo stesso risultato:
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);
}
Voglio solo spiegare una situazione più simile List<Documents>, questa lista contiene alcune liste più di altri documenti come List<Excel>, List<Word>, List<PowerPoint>. Quindi la struttura è
class A {
List<Documents> documentList;
}
class Documents {
List<Excel> excels;
List<Word> words;
List<PowerPoint> ppt;
}
Ora se vuoi iterare Excel solo dai documenti, fai qualcosa come sotto ...
Quindi il codice sarebbe
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.
}
Spero che questo possa risolvere il problema di qualcuno durante la codifica ...
Possiamo usare flatmap per questo, si prega di fare riferimento al codice seguente:
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);
Un'espansione della risposta di Eran che è stata la risposta migliore, se hai un sacco di strati di liste, puoi continuare a formarle.
Questo viene anche fornito con un pratico modo di filtrare mentre scendi i livelli, se necessario.
Quindi per esempio:
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())
Ciò sarebbe simile in SQL con le istruzioni SELECT all'interno delle istruzioni SELECT.
Metodo per convertire a List<List>in List:
listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
Vedi questo esempio:
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);
}
}
Stampa:
listOfLists => [[a, b, c]]
list => [a, b, c]
:::)