web-dev-qa-db-fra.com

Comment 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> contenant tous les objets du même ordre d'itération en utilisant les fonctions de Java 8?

437
Sarah Szabo

Vous pouvez utiliser flatMap pour aplatir les listes internes (après les avoir converties en flux) en un seul flux, puis rassembler le résultat dans une liste:

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());
791
Eran

flatmap c'est mieux mais il y a d'autres moyens pour atteindre le même objectif

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

List<Object> collect = 
      listOfList.stream()
                .collect(ArrayList::new, List::addAll, List::addAll);
42
Saravana

La méthode flatMap sur Stream peut certainement aplatir ces listes pour vous, mais elle doit créer des objets Stream pour element, 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);
_

Étant donné qu'une List est Iterable, ce code appelle la méthode forEach (fonctionnalité Java 8), qui est héritée de Iterable.

Exécute l'action donnée pour chaque élément de la Iterable jusqu'à ce que tous les éléments aient été traités ou que l'action lève une exception. Les actions sont effectuées dans l'ordre des itérations, si cet ordre est spécifié.

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

Pour la Consumer, ce code transmet une référence de méthode (fonctionnalité Java 8) à la méthode antérieure à Java 8 List.addAll pour ajouter les éléments de la liste interne de manière séquentielle.

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

20
rgettman

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 changer de liste de List:

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

Remarque: je contribue aux collections Eclipse.

12
Nikhil Nanivadekar

Comme @Saravana a mentionné:

le flatmap est meilleur, mais il existe d’autres moyens pour atteindre le même objectif.

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

Pour résumer, il y a plusieurs façons d'obtenir les mêmes résultats:

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);
}
8
Hearen

Je veux juste expliquer un scénario supplémentaire comme List<Documents>, cette liste contient quelques listes supplémentaires de documents tels que 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 utiliser Excel uniquement à partir de documents, procédez 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 ...

5
Kushwaha

Méthode de conversion de la liste de conversion en liste: ListOfLists.stream (). FlatMap (List :: stream) .collect (Collectors.toList ()); Exemple 1 :

    public class ConvertListOfListsToList {
        public static void main(String[] args) {
            List<String> StringList = Arrays.asList("Protijayi", "Gini", "Gina");
            System.out.println(StringList);
            List<List<String>> ListOfLists = new ArrayList<>();
            ListOfLists.add(StringList);

            System.out.println("ListOfLists => " + ListOfLists);

            // Now let's do this in Java 8 using FlatMap
            List<String> flatMapList = ListOfLists.stream().flatMap(List::stream).collect(Collectors.toList());

            System.out.println("FlatList =>  " + flatMapList);
/*
ListOfLists => [[Protijayi, Gini, Gina]]
FlatList =>  [Protijayi, Gini, Gina]
*/
        }

    }
1
Soudipta Dutta

Une extension de la réponse d'Eran qui était la réponse principale, si vous avez plusieurs couches de listes, vous pouvez continuer à les cartographier à plat.

Cela vient également avec un moyen pratique de filtrer les couches si nécessaire.

Donc 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())

Ceci serait similaire en SQL à avoir des instructions SELECT dans des instructions SELECT.

0
cody.tv.weber

Nous pouvons utiliser flatmap 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);
0
Pratik Pawar