it-swarm.com.de

Wie verbinde ich zwei Listen in Java?

Bedingungen: Ändern Sie nicht die ursprünglichen Listen; Nur JDK, keine externen Bibliotheken. Bonuspunkte für einen Einzeiler oder eine JDK 1.3-Version.

Gibt es einen einfacheren Weg als:

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

Vom Kopf aus kann ich es um eine Zeile kürzen:

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

In Java 8:

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

Du könntest die Apache commons-collections Bibliothek benutzen:

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

Wahrscheinlich nicht einfacher, aber faszinierend und hässlich:

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

Verwenden Sie es nicht im Produktionscode ...;)

82
volley

Eine Ihrer Anforderungen ist es, die ursprünglichen Listen beizubehalten. Wenn Sie eine neue Liste erstellen und addAll() verwenden, verdoppeln Sie effektiv die Anzahl der Verweise auf die Objekte in Ihren Listen. Dies kann zu Speicherproblemen führen, wenn Ihre Listen sehr umfangreich sind.

Wenn Sie das verkettete Ergebnis nicht ändern müssen, können Sie dies mithilfe einer benutzerdefinierten Listenimplementierung vermeiden. Die benutzerdefinierte Implementierungsklasse ist offensichtlich mehr als eine Zeile ... aber die Verwendung ist kurz und bündig.

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

Verwendungszweck:

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

Nicht einfacher, aber ohne die Größe des Overheads zu ändern:

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

Ein weiterer Java 8 Einzeiler:

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

Als Bonus können Sie beliebig viele Listen verketten, da Stream.of() variabel ist.

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

Wir haben diese Frage gefunden, um eine beliebige Anzahl von Listen zu verketten, ohne Rücksicht auf externe Bibliotheken. Vielleicht hilft es jemand anderem:

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

Nützlich, wenn Sie dieselbe Logik auf mehrere verschiedene Sammlungen in einer für () anwenden möchten.

50
Yuri Geinish

Hier ist eine Java 8-Lösung mit zwei Zeilen:

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

Beachten Sie, dass diese Methode nicht verwendet werden sollte, wenn

  • die Herkunft von newList ist nicht bekannt und kann bereits mit anderen Threads geteilt werden
  • der Stream, der newList ändert, ist ein paralleler Stream und der Zugriff auf newList ist nicht synchronisiert oder threadsicher

aufgrund von Nebeneffekten.

Beide oben genannten Bedingungen gelten nicht für den oben genannten Fall des Verbindens zweier Listen. Dies ist also sicher.

Basierend auf diese Antwort auf eine andere Frage.

37
SpaceTrucker

Dies ist einfach und nur eine Zeile, fügt aber den Inhalt von listTwo zu listOne hinzu. Müssen Sie den Inhalt wirklich in eine dritte Liste aufnehmen?

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

Die vorgeschlagene Lösung gilt für drei Listen, sie kann jedoch auch für zwei Listen angewendet werden. In Java 8 können wir Stream.of oder Stream.concat verwenden als:

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 verwendet zwei Streams als Eingabe und erstellt einen verzögert verketteten Stream, dessen Elemente alle Elemente des ersten Streams sind, gefolgt von allen Elementen des zweiten Streams. Da wir drei Listen haben, haben wir diese Methode (Stream.concat) zweimal verwendet.

Wir können auch eine Utility-Klasse mit einer Methode schreiben, die eine beliebige Anzahl von Listen verwendet (mit varargs ) und eine verkettete Liste zurückgibt als:

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

Dann können wir diese Methode anwenden als:

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

Etwas einfacher:

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

Ein bisschen kürzer wäre:

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

Sie können einen Einzeiler erstellen, wenn die Zielliste vorab deklariert wurde.

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

Sie können Ihre generische Java 8 - Dienstprogrammmethode erstellen, um eine beliebige Anzahl von Listen zu komprimieren.

@SafeVarargs
public static <T> List<T> concat(List<T>... lists) {
    return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
}
11
Daniel Hári

eine andere Einzeilerlösung mit dem Stream Java8, da flatMap bereits gebucht wurde, ist hier eine Lösung ohne flatMap

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

oder

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

ausgabe

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

In Java 8 (andersherum):

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

Das klügste meiner Meinung nach:

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

Sie können dies mit einem statischen Import und einer Hilfsklasse tun

nb Die Generierung dieser Klasse könnte wahrscheinlich verbessert werden

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

}

Dann können Sie Dinge tun wie

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

Java 8-Version mit Unterstützung für das Verknüpfen nach Objektschlüssel:

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

Verwenden Sie eine Helper-Klasse.

Ich schlage vor:

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)));
}
4
alex
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;
}
3
martyglaubitz
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;
  }
2

Kein Weg in der Nähe von Einzeiler, aber ich denke, das ist das einfachste:

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

for(String w:newList)
        System.out.printf("%s ", w);
0
nirmal

Hier ist ein Ansatz mit Streams und Java 8, wenn Ihre Listen unterschiedliche Typen haben und Sie sie zu einer Liste eines anderen Typs kombinieren möchten.

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
shinzou

Wenn Sie dies statisch tun möchten, können Sie Folgendes tun.

In den Beispielen werden 2 EnumSets in natürlicher Reihenfolge (== Enum-Reihenfolge) A, B verwendet und anschließend in eine ALL-Liste eingefügt.

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
Jan Weitz

Ich behaupte nicht, dass es einfach ist, aber Sie haben den Bonus für Einzeiler erwähnt ;-)

Collection mergedList = Collections.list(new Sun.misc.CompoundEnumeration(new Enumeration[] {
    new Vector(list1).elements(),
    new Vector(list2).elements(),
    ...
}))
0
ddimitrov
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;
    }

}
0
benez