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 flatMap
pour 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::method
se 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 flatMap
méthode sur Stream
peut certainement aplatir ces listes pour vous, mais elle doit créer des Stream
objets pour l'élément, puis un Stream
pour le résultat.
Vous n'avez pas besoin de tous ces Stream
objets. 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 List
est Iterable
, ce code appelle la forEach
méthode (fonctionnalité Java 8), héritée de Iterable
.
Exécute l'action donnée pour chaque élément du
Iterable
jusqu'à 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 List
s » Iterator
articles 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.addAll
pour 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]
::
:)