Comment joindre deux listes en Java?

Conditions: ne pas modifier les listes originales; JDK seulement, pas de bibliothèques externes. Points Bonus pour une version one-liner ou JDK 1.3.

y a-t-il un moyen plus simple que:

List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);
555
demandé sur Robert Atkins 2008-10-10 03:17:43

29 réponses

du haut de ma tête, je peux la raccourcir d'une ligne:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
451
répondu AdamC 2008-10-09 23:21:09

En Java 8:

List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
                             .collect(Collectors.toList());
386
répondu Dale Emery 2017-07-19 08:16:55

vous pouvez utiliser le Apache commons-collections bibliothèque:

List<String> newList = ListUtils.union(list1, list2);
227
répondu Guillermo 2018-06-24 14:29:47

probablement pas plus simple, mais intrigant et laid:

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };

ne l'utilisez pas dans le code de production... ;)

73
répondu volley 2012-07-08 12:47:43

une de vos exigences est de préserver les listes originales. Si vous créez une nouvelle liste et utilisez addAll() , vous doublez effectivement le nombre de références aux objets de vos listes. Cela pourrait conduire à des problèmes de mémoire si vos listes sont très grandes.

si vous n'avez pas besoin de modifier le résultat concaténé, vous pouvez éviter cela en utilisant une implémentation de liste personnalisée. La classe custom implementation est évidemment plus d'une ligne...mais l'utiliser est court et sucrée.

CompositeUnmodifiableList.java:

public class CompositeUnmodifiableList<E> extends AbstractList<E> {

    private final List<E> list1;
    private final List<E> list2;

    public CompositeUnmodifiableList(List<E> list1, List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }

    @Override
    public E get(int index) {
        if (index < list1.size()) {
            return list1.get(index);
        }
        return list2.get(index-list1.size());
    }

    @Override
    public int size() {
        return list1.size() + list2.size();
    }
}

Utilisation:

List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);
73
répondu Kevin K 2012-12-13 21:08:56

pas plus simple, mais sans redimensionnement au-dessus de la tête:

List<String> newList = new ArrayList<>(listOne.size() + listTwo.size());
newList.addAll(listOne);
newList.addAll(listTwo);
57
répondu Martin 2012-12-13 20:35:54

a trouvé cette question à la recherche de concaténer quantité arbitraire de listes, sans faire attention aux bibliothèques externes. Ainsi, peut-être cela aidera quelqu'un d'autre:

com.google.common.collect.Iterables#concat()

utile si vous voulez appliquer la même logique à un certain nombre de collections différentes dans un pour().

47
répondu Yuri Geinish 2011-07-29 13:46:36

Another Java 8 one-liner:

List<String> newList = Stream.of(listOne, listTwo)
                             .flatMap(x -> x.stream())
                             .collect(Collectors.toList());

comme bonus, puisque Stream.of() est variadique, vous pouvez concaténer autant de listes que vous le souhaitez.

List<String> newList = Stream.of(listOne, listTwo, listThree)
                             .flatMap(x -> x.stream())
                             .collect(Collectors.toList());
40
répondu Mark 2017-07-19 08:06:08

Voici une solution java 8 utilisant deux lignes:

List<Object> newList = new ArrayList<>();
Stream.of(list1, list2).forEach(newList::addAll);

sachez que cette méthode ne doit pas être utilisée si

  • l'origine de newList n'est pas connue et elle peut déjà être partagée avec d'autres fils
  • le flux qui modifie newList est un flux parallèle et l'accès à newList n'est pas synchronisé ou threadsafe

dû à un effet secondaire considération.

les Deux conditions ci-dessus ne s'appliquent pas dans le cas ci-dessus de fusionner deux listes, c'est sûr.

basé sur cette réponse à une autre question.

30
répondu SpaceTrucker 2017-07-26 06:52:07

c'est simple et seulement une ligne, mais ajoutera le contenu de listTwo à listOne. Avez-vous vraiment besoin de mettre le contenu dans une troisième liste?

Collections.addAll(listOne, listTwo.toArray());
27
répondu ceklock 2013-09-08 22:59:01

légèrement plus simple:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
19
répondu Tim 2012-03-07 17:53:02

un peu plus court serait:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
18
répondu Jorn 2008-10-09 23:22:50

la solution proposée concerne trois listes, mais elle peut aussi s'appliquer à deux listes. En Java 8, nous pouvons utiliser le flux .de ou .concat :

List<String> result1 = Stream.concat(Stream.concat(list1.stream(),list2.stream()),list3.stream()).collect(Collectors.toList());
List<String> result2 = Stream.of(list1,list2,list3).flatMap(Collection::stream).collect(Collectors.toList());

Stream.concat prend deux flux comme entrée et crée un flux paresseusement concaténé dont les éléments sont tous les éléments du premier flux suivi de tous les éléments du second flux. Comme nous l'avons trois listes que nous avons utilisé cette méthode ( Stream.concat ) deux fois.

nous pouvons aussi écrire une classe d'utilité avec une méthode qui prend n'importe quel nombre de listes (en utilisant varargs ) et retourne une liste concaténée comme:

public static <T> List<T> concatenatedList(List<T>... collections) {
        return Arrays.stream(collections).flatMap(Collection::stream).collect(Collectors.toList()); 
}

alors nous pouvons faire usage de cette méthode comme:

List<String> result3 = StringUtils.concatenatedList(list1,list2,list3);
14
répondu i_am_zero 2018-08-02 09:54:24

vous pouvez faire un oneliner si la liste cible est prédéclarée.

(newList = new ArrayList<String>(list1)).addAll(list2);
12
répondu deterb 2008-10-10 00:46:50

une autre solution de gaine utilisant Java8 stream, puisque la solution flatMap est déjà affichée, voici une solution sans flatMap

List<E> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);

ou

List<E> ints = Stream.of(list1, list2).collect(ArrayList::new, List::addAll, List::addAll);

code

    List<List<Integer>> lol = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
    List<Integer> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);
    System.out.println(lol);
    System.out.println(li);

sortie

[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]
7
répondu Saravana 2016-11-12 04:44:28

Dans Java 8 (l'autre):

List<?> newList = 
Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toList());
7
répondu Nitin Jain 2017-03-24 04:43:59

Le plus intelligent à mon avis:

/**
 * @param smallLists
 * @return one big list containing all elements of the small ones, in the same order.
 */
public static <E> List<E> concatenate (final List<E> ... smallLists)
{
    final ArrayList<E> bigList = new ArrayList<E>();
    for (final List<E> list: smallLists)
    {
        bigList.addAll(list);
    }
    return bigList;
}
5
répondu Olivier Faucheux 2012-07-26 09:25:40

version Java 8 avec prise en charge de l'adhésion par clé d'objet:

public List<SomeClass> mergeLists(final List<SomeClass> left, final List<SomeClass> right, String primaryKey) {
    final Map<Object, SomeClass> mergedList = new LinkedHashMap<>();

    Stream.concat(left.stream(), right.stream())
        .map(someObject -> new Pair<Object, SomeClass>(someObject.getSomeKey(), someObject))
        .forEach(pair-> mergedList.put(pair.getKey(), pair.getValue()));

    return new ArrayList<>(mergedList.values());
}
4
répondu cslysy 2016-11-29 15:49:17

vous pourriez le faire avec une importation statique et une classe helper

nb la généralisation de cette classe pourrait probablement être améliorée

public class Lists {

   private Lists() { } // can't be instantiated

   public static List<T> join(List<T>... lists) {
      List<T> result = new ArrayList<T>();
      for(List<T> list : lists) {
         result.addAll(list);
      }
      return results;
   }

}

alors vous pouvez faire des choses comme

import static Lists.join;
List<T> result = join(list1, list2, list3, list4);
3
répondu Dave Cheney 2013-09-08 19:43:40
public static <T> List<T> merge(List<T>... args) {
    final List<T> result = new ArrayList<>();

    for (List<T> list : args) {
        result.addAll(list);
    }

    return result;
}
2
répondu martyglaubitz 2014-07-12 17:12:52

utilisez une classe Helper.

je suggère:

public static <E> Collection<E> addAll(Collection<E> dest, Collection<? extends E>... src) {
    for(Collection<? extends E> c : src) {
        dest.addAll(c);
    }

    return dest;
}

public static void main(String[] args) {
    System.out.println(addAll(new ArrayList<Object>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    // does not compile
    // System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList(4, 5, 6)));
}
2
répondu alex 2016-10-05 10:18:11

, Vous pouvez créer votre générique Java 8 utilitaire méthode concat un certain nombre de listes .

@SafeVarargs
public static <T> List<T> concat(List<T>... lists) {
    return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
}
2
répondu Daniel Hári 2018-05-18 20:33:05

Je ne prétends pas que c'est simple, mais vous avez mentionné bonus pour les monoliers; -)

Collection mergedList = Collections.list(new sun.misc.CompoundEnumeration(new Enumeration[] {
    new Vector(list1).elements(),
    new Vector(list2).elements(),
    ...
}))
0
répondu ddimitrov 2011-05-27 17:50:08

il N'y a rien près d'une doublure, mais je pense que c'est le plus simple:

List<String> newList = new ArrayList<String>(l1);
newList.addAll(l2);

for(String w:newList)
        System.out.printf("%s ", w);
0
répondu nirmal 2011-09-06 11:06:40

voici une approche en utilisant streams et java 8 si vos listes ont des types différents et que vous voulez les combiner à une liste d'un autre type.

public static void main(String[] args) {
    List<String> list2 = new ArrayList<>();
    List<Pair<Integer, String>> list1 = new ArrayList<>();

    list2.add("asd");
    list2.add("asdaf");
    list1.add(new Pair<>(1, "werwe"));
    list1.add(new Pair<>(2, "tyutyu"));

    Stream stream = Stream.concat(list1.stream(), list2.stream());

    List<Pair<Integer, String>> res = (List<Pair<Integer, String>>) stream
            .map(item -> {
                if (item instanceof String) {
                    return new Pair<>(0, item);
                }
                else {
                    return new Pair<>(((Pair<Integer, String>)item).getKey(), ((Pair<Integer, String>)item).getValue());
                }
            })
            .collect(Collectors.toList());
}
0
répondu shinzou 2016-10-18 22:28:23

si vous voulez faire ceci statiquement vous pouvez le suivant.

les exemples utilisent 2 Énumérets dans l'ordre naturel (==enum-ordre) A, B et rejoint alors dans une liste ALL .

public static final EnumSet<MyType> CATEGORY_A = EnumSet.of(A_1, A_2);
public static final EnumSet<MyType> CATEGORY_B = EnumSet.of(B_1, B_2, B_3);

public static final List<MyType> ALL = 
              Collections.unmodifiableList(
                  new ArrayList<MyType>(CATEGORY_A.size() + CATEGORY_B.size())
                  {{
                      addAll(CATEGORY_A);
                      addAll(CATEGORY_B);
                  }}
              );
0
répondu Jan Weitz 2017-12-12 13:21:20
public static <T> List<T> merge(@Nonnull final List<T>... list) {
    // calculate length first
    int mergedLength = 0;
    for (List<T> ts : list) {
      mergedLength += ts.size();
    }

    final List<T> mergedList = new ArrayList<>(mergedLength);

    for (List<T> ts : list) {
      mergedList.addAll(ts);
    }

    return mergedList;
  }
0
répondu Langusten Gustel 2018-02-21 11:11:36
public class TestApp {

/**
 * @param args
 */
public static void main(String[] args) {
    System.out.println("Hi");
    Set<List<String>> bcOwnersList = new HashSet<List<String>>();
    List<String> bclist = new ArrayList<String>();
    List<String> bclist1 = new ArrayList<String>();
    List<String> object = new ArrayList<String>();
    object.add("BC11");
    object.add("C2");
    bclist.add("BC1");
    bclist.add("BC2");
    bclist.add("BC3");
    bclist.add("BC4");
    bclist.add("BC5");
    bcOwnersList.add(bclist);
    bcOwnersList.add(object);

    bclist1.add("BC11");
    bclist1.add("BC21");
    bclist1.add("BC31");
    bclist1.add("BC4");
    bclist1.add("BC5");

    List<String> listList= new ArrayList<String>();
    for(List<String> ll : bcOwnersList){
        listList = (List<String>) CollectionUtils.union(listList,CollectionUtils.intersection(ll, bclist1));
    }
    /*for(List<String> lists : listList){
        test = (List<String>) CollectionUtils.union(test, listList);
    }*/
    for(Object l : listList){
        System.out.println(l.toString());
    }
    System.out.println(bclist.contains("BC"));

}

}
-4
répondu Ram Pasupula 2012-12-21 12:55:36

Je ne peux pas améliorer le double-liner dans le cas général sans introduire votre propre méthode d'utilité, mais si vous avez des listes de chaînes et vous êtes prêt à supposer que ces chaînes ne contiennent pas de virgule, Vous pouvez tirer ce long one-liner:

List<String> newList = new ArrayList<String>(Arrays.asList((listOne.toString().subString(1, listOne.length() - 1) + ", " + listTwo.toString().subString(1, listTwo.length() - 1)).split(", ")));

si vous abandonnez les génériques, cela devrait être JDK conforme 1.4 (bien que je n'ai pas testé cela). Également déconseillé pour le code de production; -)

-5
répondu Dov Wasserman 2008-10-10 04:52:07