0
votes

Fusionner plusieurs listes en une seule liste en conservant l'ordre des éléments de la liste d'entrée

Exigence:

Entrée: liste d'entiers.

Liste1: [1,2,3]

Liste 2: [4,5,6]

Liste 3: [7,8,9]

Sortie: [1, 4, 7, 2, 5, 8, 3, 6, 9]

Hypothèse: chaque liste sera de la même taille.

Voici ma mise en œuvre initiale qui, selon moi, n'est pas très optimale. Y a-t-il un meilleur moyen?

    List<Integer> one = Arrays.asList(1, 2,3);
    List<Integer> two = Arrays.asList(4, 5,6);
    List<Integer> three = Arrays.asList(7, 8, 9);
    List<Integer> out = new ArrayList<>();
    for(int i=0; i< one.size(); i++){
        final int index = i;
        out.addAll(Stream.of(one, two, three)
                .collect(ArrayList::new, 
                        (listStream, item) -> listStream.add(item.get(index)), 
                        (item1, item2) -> {}));
    }
    System.out.println(out);

Sortie: [1, 4, 7, 2, 5, 8, 3, 6, 9]


0 commentaires

4 Réponses :


3
votes

Vous pourriez faire

List<Integer> one = Arrays.asList(1, 2, 3);
List<Integer> two = Arrays.asList(4, 5, 6);
List<Integer> three = Arrays.asList(7, 8, 9);

List<Iterator<Integer>> its = Stream.of(one, two, three).map(Iterable::iterator).collect(Collectors.toList());
List<Integer> out = new ArrayList<>();

while (true) {
    try {
        for (Iterator<Integer> it : its) {
            out.add(it.next());
        }
    } catch (NoSuchElementException ignored) {
        break;
    }
}
System.out.println(out);

Sortie: [1, 4, 7, 2, 5, 8, 3, 6, 9]

Si ces listes peuvent devenir longues, utiliser un itérateur pourrait être mieux que d'accéder aux éléments en utilisant get positionnel, par exemple

List<Integer> one = Arrays.asList(1, 2, 3);
List<Integer> two = Arrays.asList(4, 5, 6);
List<Integer> three = Arrays.asList(7, 8, 9);

List<List<Integer>> lists = Arrays.asList(one, two, three);
List<Integer> out = IntStream.range(0, one.size())
    .mapToObj(i -> lists.stream().map(list -> list.get(i)))
    .flatMap(Function.identity())
    .collect(Collectors.toList());

System.out.println(out);


0 commentaires

0
votes

Tant qu'il s'agit d'itérer plusieurs collections simultanément, je préfère utiliser Iterator sur Stream API car vous avez plus de contrôle.

Iterator<Integer> iterator1 = one.iterator();
Iterator<Integer> iterator2 = two.iterator();
Iterator<Integer> iterator3 = three.iterator();

while (iterator1.hasNext() || iterator2.hasNext() || iterator3.hasNext()) {
    if (iterator1.hasNext()) out.add(iterator1.next());
    if (iterator2.hasNext()) out.add(iterator2.next());
    if (iterator3.hasNext()) out.add(iterator3.next());
}

System.out.println(out);

Avantages:

  • Facile à lire et à maintenir l'ordre.
  • Sans danger pour la taille variable des collections (bien que vous ayez déclaré que c'était fixe - pouvez-vous vraiment vous fier à cela?)
  • Les itérateurs eux-mêmes peuvent également être dans une autre collection.

Les inconvénients:

  • Vérifiez à nouveau Iterator::hasNext .
  • N'est pas conforme à Stream API (ce qui est plus une caractéristique qu'un inconvénient).


0 commentaires

1
votes

Vous pourriez le faire comme ça.

List<Integer> result2 = new ArrayList<>();

for (int i = 0; i < lists.get(0).size(); i++) {
    for (List<Integer> lst : lists) {
        result2.add(lst.get(i));
    }
}

System.out.println(result2);

Tirages

[1, 4, 7, 2, 5, 8, 3, 6, 9]

Mais alors, cela fonctionne aussi.

List<List<Integer>> lists = List.of(List.of(1, 2, 3),
        List.of(4, 5, 6), List.of(7, 8, 9));

List<Integer> result = IntStream.range(0, lists.get(0).size())
        .boxed()
        .flatMap(i -> lists.stream().map(lst->lst.get(i)))
        .collect(Collectors.toList());

System.out.println(result);


0 commentaires

0
votes

Une autre solution facile à comprendre:

IntStream.range(0, one.size())
  .mapToObj(index -> new int[]{one.get(index), two.get(index), three.get(index)})
        .forEach(x -> {System.out.print(x[0] + ", " + x[1] + ", " + x[2] + ", ");});


0 commentaires