Hoe voeg ik twee lijsten in Java toe?

Voorwaarden: wijzig de originele lijsten niet; Alleen JDK, geen externe bibliotheken. Bonuspunten voor een oneliner of een JDK 1.3-versie.

Is er een eenvoudigere manier dan:

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

Antwoord 1, autoriteit 100%

In Java 8:

List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
                             .collect(Collectors.toList());

Antwoord 2, autoriteit 87%

Zo uit mijn hoofd, ik kan het met één regel inkorten:

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

Antwoord 3, autoriteit 48%

Je zou de Apache commons kunnen gebruiken -collectiesbibliotheek:

List<String> newList = ListUtils.union(list1, list2);

Antwoord 4, autoriteit 22%

Nog een Java 8 oneliner:

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

Als bonus, aangezien Stream.of()variadisch is, kunt u zoveel lijsten aaneenschakelen als u wilt.

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

5, Autoriteit 13%

Een van uw vereisten is om de originele lijsten te behouden. Als u een nieuwe lijst maakt en addAll()gebruikt, verdubbelt u effectief het aantal verwijzingen naar de objecten in uw lijsten. Dit kan leiden tot geheugenproblemen als uw lijsten erg groot zijn.

Als u het aaneengesloten resultaat niet hoeft te wijzigen, kunt u dit voorkomen met behulp van een implementatie van een aangepaste lijst. De aangepaste implementatieklasse is meer dan één regel, uiteraard … maar het is kort en zoet.

CompositeUnmodifiLelist.java:

public class CompositeUnmodifiableList<E> extends AbstractList<E> {
    private final List<? extends E> list1;
    private final List<? extends E> list2;
    public CompositeUnmodifiableList(List<? extends E> list1, List<? extends 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();
    }
}

Gebruik:

List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);

6, Autoriteit 13%

Waarschijnlijk niet eenvoudiger, maar intrigerend en lelijk:

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

Gebruik het niet in productiecode… 😉


Antwoord 7, autoriteit 11%

Niet eenvoudiger, maar zonder de grootte van de overhead te wijzigen:

List<String> newList = new ArrayList<>(listOne.size() + listTwo.size());
newList.addAll(listOne);
newList.addAll(listTwo);

Antwoord 8, autoriteit 8%

Ik vond deze vraag om een willekeurig aantal lijsten samen te voegen, zonder rekening te houden met externe bibliotheken. Dus misschien helpt het iemand anders:

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

Handig als u dezelfde logica wilt toepassen op een aantal verschillende collecties in één for().


Antwoord 9, autoriteit 7%

Java 8 (Stream.ofen Stream.concat)

De voorgestelde oplossing is voor drie lijsten, maar kan ook voor twee lijsten worden toegepast. In Java 8 kunnen we gebruik maken van Stream.ofof Stream.concatals:

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.concatneemt twee streams als invoer en maakt een lui aaneengeschakelde stream waarvan de elementen alle elementen van de eerste stream zijn, gevolgd door alle elementen van de tweede stream. Omdat we drie lijsten hebben, hebben we deze methode (Stream.concat) twee keer gebruikt.

We kunnen ook een utility-klasse schrijven met een methode die een willekeurig aantal lijsten nodig heeft (met behulp van varargs) en retourneert een aaneengeschakelde lijst als:

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

Dan kunnen we deze methode gebruiken als:

List<String> result3 = Utils.concatenateLists(list1,list2,list3);

Antwoord 10, autoriteit 7%

Hier is een Java 8-oplossing met twee regels:

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

Houd er rekening mee dat deze methode niet mag worden gebruikt als

  • de oorsprong van newListis niet bekend en is mogelijk al gedeeld met andere threads
  • de stream die newListwijzigt, is een parallelle stream en toegang tot newListis niet gesynchroniseerd of threadsafe

vanwege bijwerkingen.

Beide bovenstaande voorwaarden zijn niet van toepassing op het bovenstaande geval van deelname aan twee lijsten, dus dit is veilig.

Gebaseerd op dit antwoordop een andere vraag.


11, Autoriteit 5%

Dit is eenvoudig en slechts één regel, maar voegt de inhoud van Listtwo toe aan Listone. Moet u echt de inhoud plaatsen in een derde lijst?

Collections.addAll(listOne, listTwo.toArray());

12, Autoriteit 4%

iets eenvoudiger:

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

13, Autoriteit 3%

Een beetje korter zou zijn:

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

14, Autoriteit 2%

U kunt een OEKERINER doen als de doellijst wordt vooraf.

(newList = new ArrayList<String>(list1)).addAll(list2);

15, Autoriteit 2%

In Java 8 (de andere kant op):

List<?> newList = 
Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toList());

16

Nog een voeringoplossing met Java8STREAM, Aangezien flatMapOplossing is al gepost, hier is een oplossing zonder flatMap

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

of

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);

Uitgang

[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]

17

De slimste naar mijn mening:

/**
 * @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;
}

18

We kunnen toetreden tot 2 lijsten met Java8 met 2 benaderingen.

   List<String> list1 = Arrays.asList("S", "T");
    List<String> list2 = Arrays.asList("U", "V");

1) Concat gebruiken:

   List<String> collect2 = Stream.concat(list1.stream(), list2.stream()).collect(toList());
    System.out.println("collect2 = " + collect2); // collect2 = [S, T, U, V]

2) FlatMap gebruiken:

   List<String> collect3 = Stream.of(list1, list2).flatMap(Collection::stream).collect(toList());
    System.out.println("collect3 = " + collect3); // collect3 = [S, T, U, V]

Antwoord 19

Bijna alle antwoorden suggereren het gebruik van een ArrayList.

List<String> newList = new LinkedList<>(listOne);
newList.addAll(listTwo);

Gebruik bij voorkeur een LinkedList voor efficiënte toevoegingen.

ArrayList add is O(1) afgeschreven, maar O(n) in het slechtste geval, aangezien de grootte van de array moet worden gewijzigd en gekopieerd.
Terwijl LinkedList toevoegen altijd constant O(1) is.

meer informatie https://stackoverflow.com/a/322742/311420


Antwoord 20

Je zou het kunnen doen met een statische import en een hulpklasse

nbhet genereren van deze klasse kan waarschijnlijk worden verbeterd

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;
   }
}

Dan kun je dingen doen als

import static Lists.join;
List<T> result = join(list1, list2, list3, list4);

Antwoord 21

Java 8-versie met ondersteuning voor deelname via objectsleutel:

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());
}

Antwoord 22

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;
}

Antwoord 23

Gebruik een Helper-klasse.

Ik stel voor:

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

Antwoord 24

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;
  }

Antwoord 25

Ik beweer niet dat het eenvoudig is, maar je noemde bonus voor oneliners 😉

Collection mergedList = Collections.list(new sun.misc.CompoundEnumeration(new Enumeration[] {
    new Vector(list1).elements(),
    new Vector(list2).elements(),
    ...
}))

Antwoord 26

Geen sprake van one-liner, maar ik denk dat dit de eenvoudigste is:

List<String> newList = new ArrayList<String>(l1);
newList.addAll(l2);
for(String w:newList)
        System.out.printf("%s ", w);

Antwoord 27

Hier is een benadering met behulp van streams en java 8 als uw lijsten verschillende typen hebben en u ze wilt combineren tot een lijst van een ander 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());
}

Antwoord 28

Als u dit statisch wilt doen, kunt u het volgende doen.

De voorbeelden gebruiken 2 EnumSets in natuurlijke volgorde (==Enum-volgorde) A, Ben voegt zich vervolgens in een ALLlijst.

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

Antwoord 29

import java.util.AbstractList;
import java.util.List;
/**
 * The {@code ConcatList} is a lightweight view of two {@code List}s.
 * <p>
 * This implementation is <em>not</em> thread-safe even though the underlying lists can be.
 * 
 * @param <E>
 *            the type of elements in this list
 */
public class ConcatList<E> extends AbstractList<E> {
    /** The first underlying list. */
    private final List<E> list1;
    /** The second underlying list. */
    private final List<E> list2;
    /**
     * Constructs a new {@code ConcatList} from the given two lists.
     * 
     * @param list1
     *            the first list
     * @param list2
     *            the second list
     */
    public ConcatList(final List<E> list1, final List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }
    @Override
    public E get(final int index) {
        return getList(index).get(getListIndex(index));
    }
    @Override
    public E set(final int index, final E element) {
        return getList(index).set(getListIndex(index), element);
    }
    @Override
    public void add(final int index, final E element) {
        getList(index).add(getListIndex(index), element);
    }
    @Override
    public E remove(final int index) {
        return getList(index).remove(getListIndex(index));
    }
    @Override
    public int size() {
        return list1.size() + list2.size();
    }
    @Override
    public boolean contains(final Object o) {
        return list1.contains(o) || list2.contains(o);
    }
    @Override
    public void clear() {
        list1.clear();
        list2.clear();
    }
    /**
     * Returns the index within the corresponding list related to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the index of the underlying list
     */
    private int getListIndex(final int index) {
        final int size1 = list1.size();
        return index >= size1 ? index - size1 : index;
    }
    /**
     * Returns the list that corresponds to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the underlying list that corresponds to that index
     */
    private List<E> getList(final int index) {
        return index >= list1.size() ? list2 : list1;
    }
}

Other episodes