Comment puis-je transformer une liste de listes en une liste dans Java 8?

Si j'ai un List<List<Object>>, comment puis-je le transformer en un List<Object> qui contient tous les objets dans la même itération de commande en utilisant les fonctionnalités de Java 8?

303
demandé sur Michael 2014-08-05 23:48:00

6 réponses

Vous pouvez utiliser flatMap pour aplatir le les listes internes (après les convertir en Flux) en un seul Flux, puis recueillir le résultat dans une liste:

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());
569
répondu Eran 2018-03-21 12:25:32

flatmap c'est mieux mais il y a d'autres façons d'atteindre le même

List<List<Object>> listOfList = ... // fill

List<Object> collect = 
      listOfList.stream()
                .collect(ArrayList::new, List::addAll, List::addAll);
29
répondu Saravana 2018-09-12 12:59:15

Vous pouvez utiliser le modèle flatCollect() de Eclipse Collections .

MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);

Si vous ne pouvez pas modifier la liste de List:

List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);

Remarque: je suis un contributeur aux Collections Eclipse.

13
répondu Nikhil Nanivadekar 2016-03-27 00:04:46

Le flatMap méthode sur Stream peut certainement aplatir ces listes pour vous, mais il doit créer Stream objets pour l'élément, puis un Stream pour le résultat.

Vous n'avez pas besoin de tous ces objets Stream. 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 qu'un List est Iterable, ce code appelle la méthode forEach (fonctionnalité Java 8), qui est héritée de Iterable.

Effectue l'action donnée pour chaque élément du Iterable jusqu'à ce que tous les éléments ont été traitées ou l'action lève une exception. Les Actions sont effectuées dans l'ordre d'itération, si cet ordre est spécifié.

Et un List Iterator renvoie les éléments dans un ordre séquentiel.

Pour le Consumer, ce code passe dans une référence de méthode (fonctionnalité Java 8) à la méthode pré-Java 8List.addAll pour ajouter les éléments de liste interne séquentiellement.

Ajoute tous les éléments de la collection spécifiée à la fin de cette liste, dans l'ordre qu'ils sont retournés par l'itérateur de la collection spécifiée (opération facultative).

10
répondu rgettman 2018-05-11 23:04:25

Tout comme @ Saravana mentionné:

Flatmap est mieux, mais il y a d'autres façons d'atteindre le même

 listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
 });

Pour résumer, il y a plusieurs façons d'atteindre le même 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);
}
4
répondu Hearen 2018-06-25 22:35:17

Je veux juste expliquer un scénario plus comme List<Documents>, cette liste contient un peu plus de listes d'autres documents comme List<Excel>, List<Word>, List<PowerPoint>. Donc la structure est

Class A{
  List<Documents> documentList
}

Class Documents{
  List<Excel> excels
  List<Word> words
  List<PowerPoint> ppt
}

Maintenant, si vous voulez itérer Excel uniquement à partir de documents, faites quelque chose comme ci-dessous..

Donc le code serait

 List<Document> 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 pendant le codage..

1
répondu Kushwaha 2018-03-22 09:23:14