Si j'ai un List<List<Object>>, comment puis-je le transformer en un List<Object>qui contient tous les objets dans le même ordre d'itération en utilisant les fonctionnalités de Java 8?
Si j'ai un List<List<Object>>, comment puis-je le transformer en un List<Object>qui contient tous les objets dans le même ordre d'itération en utilisant les fonctionnalités de Java 8?
Réponses:
Vous pouvez utiliser flatMappour aplatir les listes internes (après les avoir converties en flux) en un seul flux, puis collecter le résultat dans une liste:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
Class::methodse sent un peu bizarre au début, mais il a l'avantage de déclarer le type d'objet à partir duquel vous effectuez le mappage. C'est quelque chose que vous perdez autrement dans les flux.
La flatMapméthode sur Streampeut certainement aplatir ces listes pour vous, mais elle doit créer des Streamobjets pour l'élément, puis un Streampour le résultat.
Vous n'avez pas besoin de tous ces Streamobjets. Voici le code simple et concis pour effectuer la tâche.
// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);
Parce que a Listest Iterable, ce code appelle la forEachméthode (fonctionnalité Java 8), héritée de Iterable.
Exécute l'action donnée pour chaque élément du
Iterablejusqu'à ce que tous les éléments aient été traités ou que l'action lève une exception. Les actions sont exécutées dans l'ordre d'itération, si cet ordre est spécifié.
Et un Lists » Iteratorarticles de retours dans un ordre séquentiel.
Pour le Consumer, ce code transmet une référence de méthode (fonctionnalité Java 8) à la méthode pré-Java 8 List.addAllpour ajouter séquentiellement les éléments de la liste interne.
Ajoute tous les éléments de la collection spécifiée à la fin de cette liste, dans l'ordre où ils sont renvoyés par l'itérateur de la collection spécifiée (opération facultative).
Vous pouvez utiliser le flatCollect()modèle des collections Eclipse .
MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);
Si vous ne pouvez pas modifier la liste depuis List:
List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);
Remarque: je suis un contributeur aux collections Eclipse.
Tout comme @Saravana l'a mentionné:
flatmap est mieux, mais il existe d'autres façons d'obtenir le même
listStream.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});
Pour résumer, il existe plusieurs façons d’obtenir les mêmes résultats comme suit:
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);
}
Je veux juste expliquer un scénario plutôt List<Documents>, cette liste contient quelques listes de plus d'autres documents comme List<Excel>, List<Word>, List<PowerPoint>. La structure est donc
class A {
List<Documents> documentList;
}
class Documents {
List<Excel> excels;
List<Word> words;
List<PowerPoint> ppt;
}
Maintenant, si vous souhaitez itérer Excel uniquement à partir de documents, faites quelque chose comme ci-dessous.
Donc, le code serait
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.
}
J'espère que cela peut résoudre le problème de quelqu'un lors du codage ...
Nous pouvons utiliser une carte plate pour cela, veuillez vous référer au code ci-dessous:
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);
Une extension de la réponse d'Eran qui était la meilleure réponse, si vous avez un tas de couches de listes, vous pouvez continuer à les cartographier à plat.
Cela est également livré avec un moyen pratique de filtrer lorsque vous descendez les couches si nécessaire.
Ainsi, par exemple:
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())
Cela serait similaire en SQL à avoir des instructions SELECT dans les instructions SELECT.
Méthode pour convertir un List<List>en List:
listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());
Voir cet exemple:
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);
}
}
Il imprime:
listOfLists => [[a, b, c]]
list => [a, b, c]
:::)