Как мне объединить два списка в Java?

Условия: не изменяйте исходные списки; Только JDK, без внешних библиотек. Бонусные баллы за однострочную версию или версию JDK 1.3.

Есть ли способ попроще, чем:

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

Если вы делаете это исключительно для целей итерации, см. Другой вопрос - есть решения google guava и java 8 stackoverflow.com/questions/4896662/…

Boris Treukhov 07.07.2014 19:43

Решение Java 8 с служебным методом: stackoverflow.com/a/37386846/1216775

akhil_mittal 29.04.2017 08:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
834
2
953 886
32

Ответы 32

Чуть проще:

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

Будет ли это вызывать дублирование строк? Значит, строка, которая существует в обоих списках, будет существовать дважды в результирующем списке?

AgentKnopf 13.06.2012 14:33

@Zainodis Да, дубликаты могут быть. Структура List не накладывает ограничений на уникальность. Вы можете удалить дубли, проделав то же самое с наборами. Set<String> newSet = new HashSet<>(setOne); newSet.addAll(setTwo);

Patrick 27.12.2012 21:01

С макушки я могу сократить его на одну строчку:

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

Хотя вы технически правы, вы сократили его на одну строчку, асимметрия этого меня беспокоит. Достаточно, чтобы я с удовольствием «потратил» лишнюю строчку.

Robert Atkins 15.12.2011 04:54

Разве здесь не проблема, когда внутренний массив newList будет инициализирован размером listOne, а затем должен потенциально расширяться при добавлении всех элементов из listTwo? Было бы лучше взять размер каждого списка и использовать его для определения размера нового массива?

Eric 02.03.2016 11:38

Это было решение, которое лучше всего сработало для меня. Я провел сравнение производительности различных решений, и оно оказалось победителем, вместе с созданием пустого списка, а затем addAll() обоих. Я перепробовал все те, которые предлагают не копировать списки, и в результате возникают большие накладные расходы, которые нам не понадобились на этот раз.

manuelvigarcia 26.09.2016 09:46

Используйте LinkedList вместо ArrayList для эффективного добавления. stackoverflow.com/a/322742/311420

Raymond Chenon 07.04.2020 17:49

Чуть короче было бы:

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

Наверное, не проще, но интригующе и некрасиво:

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

Не используйте его в производственном коде ...;)

Безответственное использование анонимного класса. Как сказал OPP - не используйте его в производственном коде.

ddimitrov 10.10.2008 17:55

Уродливый и злой, как почти любое использование инициализации двойных скобок. Хотя короче;)

Jorn 16.08.2009 00:50

+1, приятно. Хотя Eclipse для меня разбивает более шести строк и сообщает мне @SuppressWarnings("serial"). :-)

MarnixKlooster ReinstateMonica 07.05.2011 10:28

@MarnixKlooster: Eclipse знает, что вы не должны его использовать, и это делает его использование неприятным ;-)

Joachim Sauer 03.10.2011 11:06

который известен как «объект двойной скобки», который очень удобен в тестовом коде junit для создания объекта, который возвращает заданное значение, поскольку вы можете сразу вызвать защищенный установщик и передать некоторую последнюю ссылку на тестовые данные. затем снова с хорошей фреймворком для насмешек ...

simbo1905 01.08.2012 17:53

Хотя физически это одна строка, я не считаю это однострочным.

splungebob 14.12.2012 01:28

почему люди ненавидят инициализаторы анонимных блоков

NimChimpsky 21.12.2012 17:01

@NimChimpsky Я думаю, это в основном потому, что это не просто инициализатор анонимного блока, а вы фактически создаете анонимный подкласс ArrayList. При этом, если вы доверяете результатам этого Вопрос инициализации двойной скобки, создается впечатление, что ненависть к DBI - это в основном вопрос стилистического вкуса и микрооптимизации. Насколько я могу судить, за это нет серьезных штрафов. Подлый недостаток будет, если вы когда-нибудь попытаетесь сравнить его класс, потому что это не будет ArrayList.

Patrick 27.12.2012 21:15

@MarnixKlooster не говорит вам добавлять предупреждения о подавлении, он сообщает вам, что что-то не так с кодом, и, конечно же, «если вы установите уровень журнала на FATAL, вы не получите сообщения DEBUG»

TWiStErRob 28.08.2013 19:25

Как использование инициализации двойной скобки делает его однострочным?

Jimmy T. 09.09.2013 03:14

@NimChimpsky еще одна причина, по которой инициализаторы анонимных блоков могут быть злом, заключается в том, что они будут пропускать внешний экземпляр объекта так же, как любой анонимный класс в Java. Однако использование в статических методах должно быть безопасным.

riwnodennyk 28.12.2016 15:31

@NimChimpsky Вы можете ознакомиться с этой статьей о недостатках инициализации двойных скобок: Не будь «умным»: анти-узор с двойными фигурными скобками

Alex 30.05.2017 10:41

Вы можете сделать однострочник, если целевой список заранее объявлен.

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

Вы можете сделать это с помощью статического импорта и вспомогательного класса

nb генерацию этого класса, вероятно, можно было бы улучшить

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

}

Тогда вы можете делать такие вещи, как

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

Каким образом актуален статический импорт или вспомогательный класс?

shmosel 31.05.2019 00:02

Я не могу улучшить двухстрочный интерфейс в общем случае, не вводя ваш собственный служебный метод, но если у вас есть списки строк, и вы готовы предположить, что эти строки не содержат запятых, вы можете вытащить этот длинный -лайнер:

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

Если вы откажетесь от дженериков, они должны быть совместимы с JDK 1.4 (хотя я этого не тестировал). Также не рекомендуется для производственного кода ;-)

Это отвратительная строчка кода. Вероятно, более высокая производительность, чем все другие решения (вместе взятые), делает массу предположений, которые вам действительно не нужно делать, на самом деле не однострочный (вы можете поместить всю программу в одну строку технически).

luk2302 17.08.2016 18:03

@ luk2302 Однако не содержит точек с запятой (кроме конца), поэтому его можно рассматривать как однострочное.

Egor Hans 02.09.2017 12:24

о, боже, а что, если в элементах списка есть запятая?

regulus 27.08.2020 01:36

Я не утверждаю, что это просто, но вы упомянули бонус за однострочники ;-)

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

почему кто-то никогда не должен их использовать?

David 03.06.2013 20:27

@David, потому что он предназначен для внутреннего использования в JDK. Если вы использовали это в своем коде, ваш код, скорее всего, не будет работать не на Sun (или не на Oracle сейчас) JDK / JRE.

Adrian Shum 23.07.2013 11:06

@AdrianShum Существуют ли другие JDK / JRE, кроме Oracle? Это бы меня удивило. Даже если ограничиться наиболее распространенной функциональностью API, восстановление всего этого, вероятно, займет много времени ...

Egor Hans 02.09.2017 13:52

JVM довольно много. Чаще всего в корпоративном мире используется IBM, который, iirc, связан с websphere.

Adrian Shum 02.09.2017 14:41

всякий раз, когда вы видите использование Vector, сделайте 5-минутный перерыв.

bvdb 22.07.2020 18:11

Используйте вспомогательный класс.

Я предлагаю:

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

Вы можете использовать библиотеку Коллекции общего пользования Apache:

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

Красиво, но требует общих ресурсов Apache. Он не указал «никаких внешних библиотек»

Quantum7 26.04.2011 05:17

@ Quantum7, все еще полезно для других;) Кроме того, apache commons даже внешняя библиотека? Я без него ничего не запускаю!

tster 31.03.2012 03:31

@Platinum Нет, согласно документации ListUtils.union в точности эквивалентен коду OP. Но, возможно, использование операции SET («Объединение») в контексте списка ошибочно. Я вижу, как вы могли ожидать, что это удалит дубликаты или что-то в этом роде, но похоже, что метод этого не делает.

Quantum7 18.12.2012 03:52

Избегайте коллекций Apache Commons. Это небезопасно, здесь нет дженериков. Отлично, если вы используете Java 1.4, но для Java 5 и выше я бы предпочел Google Guava.

Michael Piefel 08.09.2013 23:37

@MichaelPiefel кажется, что единственный метод, отсутствующий в Guava, - это метод Lists.concat (...).

Richard 22.11.2013 14:34

@ Ричард Да, а как насчет Iterables.concat()? В большинстве случаев это именно то, что вы хотите. Если вам абсолютно необходим новый список, используйте Lists.newArrayList(Iterables.concat(…)).

Michael Piefel 25.11.2013 13:35

@MichaelPiefel Последняя версия Apache Commons Collections 4 является типобезопасной. Благодаря справочнику по методам Java 8 статические утилиты такого типа становятся очень важными.

mingfai 21.01.2014 22:17

ListUtils от Apache - очень хорошая библиотека, простая в использовании ListUtils.uniion (list1, list2), как вы говорите, но нужны ли вам другие методы, например longestCommonSubsequence (...) или fixedSizeList (...)? Может быть полезно подумать о том, что еще перетаскивается, что вам может не понадобиться, когда так легко объединить списки, как List.addAll ()

Tzen 15.12.2016 14:20

Проголосовали за, так как это единственный ответ, для которого не требовалось несколько вызовов методов. Потоки - это весело, но необходимость делать n вызовов методов для каждой ... одной ... мелочи ... кажется подверженной ошибкам. Объединение двух списков ДОЛЖНО быть простой операцией.

Michael Haefele 25.10.2017 16:30

К сожалению, ListUtils.union () не поддерживает более двух параметров.

Pat Myron 09.05.2018 03:14

Нашел этот вопрос, пытаясь объединить произвольное количество списков, не обращая внимания на внешние библиотеки. Так что, возможно, это поможет кому-то другому:

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

Полезно, если вы хотите применить одну и ту же логику к нескольким различным коллекциям в одной for ().

Например: Lists.newArrayList (Iterables.concat (list1, list2));

meilechh 13.02.2014 21:14

вы должны вызвать com.google.common.collect.Iterators#concat(java.util.Iterato‌​r<? extends java.util.Iterator<? extends T>>) вместо Iterables#concat(); потому что последние по-прежнему копируют элементы во временную ссылку!

bob 14.04.2016 09:36

Никаких однострочных, но я думаю, что это самый простой вариант:

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

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

Самый умный на мой взгляд:

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

Не забывайте @SafeVarargs!

Radon Rosborough 07.12.2014 19:00

Не проще, но без накладных расходов на изменение размера:

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

Одно из ваших требований - сохранить исходные списки. Если вы создаете новый список и используете addAll(), вы фактически удваиваете количество ссылок на объекты в ваших списках. Это может привести к проблемам с памятью, если ваши списки очень большие.

Если вам не нужно изменять объединенный результат, вы можете избежать этого, используя реализацию настраиваемого списка. Пользовательский класс реализации, очевидно, состоит из нескольких строк ... но его использование короткое и приятное.

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

Использование:

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

Это работоспособное решение, но имейте в виду, что если изменяются базовые объекты списка (list1, list2), содержимое этого списка изменяется. Возможно, вы не сможете изменить экземпляр CompositeUnmodifiableList сам, но если вы можете получить ссылку на исходные списки, то сможете. Также для тех, кто незнаком: последний модификатор просто влияет на Справка, сам объект списка не может измениться, но содержимое списка все еще может измениться!

jwj 16.09.2014 07:34

@jwj, все очень хорошие моменты, спасибо. Название класса, вероятно, заслуживает некоторого пояснения. Я вижу, что этот класс делает что-то очень похожее на метод Collections.unmodifiableList(), который обертывает список, чтобы сделать его неизменяемым. CompositeUnmodifiableList делает то же самое, за исключением того, что он объединяет два списка и обеспечивает объединенное представление. Все замечания, которые вы говорите о CompositeUnmodifiableList, справедливы и для Collections.unmodifiableList().

Kevin K 23.02.2015 19:22

Конструктор может принимать List<? extends E>

Patrick Parker 05.02.2017 16:48

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

}

}

Я даже не понимаю, какая часть на самом деле должна быть ответом ...

Egor Hans 02.09.2017 13:57

Несколько предложений с объяснением очень помогут. Имейте это в виду для будущих комментариев

FishingIsLife 30.12.2019 11:46

В Java 8:

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

Gawd, это что-то в Java 8? Технически ты выиграешь, я полагаю, но это чертовски длинная очередь :-)

Robert Atkins 10.09.2013 00:03

Интересно, оказывает ли создание и выполнение двух потоков заметное влияние на производительность. Я полагаю, что этого не должно быть, по сравнению с созданием двух итераторов.

Jorn 05.09.2016 19:02

Для случайного читателя есть более короткое решение, использующее также Java _ Streams: stackoverflow.com/a/34090554/363573

Stephan 04.10.2016 16:16

Это некрасиво, но, по крайней мере, свободно и может использоваться без многострочных лямбда-выражений. Я действительно хотел бы, чтобы был свободный addAll, который возвращал бы объединенный список.

Usman Ismail 11.01.2018 18:06

Думаю, стоит отметить, что и из этого действительно легко получить четкий список, например: List<String> newList = Stream.concat(listOne.stream(), listTwo.stream()).distinct().collect(Collectors.toList());

Roger 30.12.2018 22:18

Альтернатива concat: поток потоков Stream.of(listOne, listTwo).flatMap(Collection::stream).collect(Collectors.toLi‌​st())

Peter Walser 09.04.2019 14:17

По сути, это то же самое, что и C# List<string> l = list1.Union(list2).ToList();, но гораздо более подробный.

zh chen 27.12.2019 10:08

@PeterWalser Это должен быть отдельный ответ, поскольку он также позволяет использовать более одного списка. flatMap, хороший звонок!

Raphael 27.08.2020 15:05

Обычно, когда я дохожу до точки, когда единственный разумный API - это API для потоков, я понимаю, что listOne и listTwo должны были быть потоками все время.

Raphael 27.08.2020 15:06

Это просто и всего одна строка, но добавит содержимое listTwo в listOne. Вам действительно нужно поместить содержимое в третий список?

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

Не изменять исходные списки было одним из критериев, но это полезно иметь здесь в качестве примера для ситуаций, когда это не ограничение.

Robert Atkins 10.09.2013 00:01

Спасибо, а то еще проще listOne.addAll (listTwo)

Jay 03.01.2020 19:23

Еще один однострочник Java 8:

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

В качестве бонуса, поскольку Stream.of() является вариативным, вы можете объединить столько списков, сколько захотите.

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

x -> x.stream() можно заменить на Collection::stream.

Martin 29.05.2015 19:18

... или даже с List::stream.

MC Emperor 11.01.2019 13:34

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

Вот решение java 8 с использованием двух строк:

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

Имейте в виду, что этот метод не следует использовать, если

  • происхождение newList неизвестно, и, возможно, он уже используется другими потоками
  • поток, изменяющий newList, является параллельным потоком, и доступ к newList не синхронизирован или не является потокобезопасным

из-за побочных эффектов.

Оба вышеуказанных условия не применимы к вышеуказанному случаю объединения двух списков, так что это безопасно.

На основании этот ответ к другому вопросу.

Если я не ошибаюсь, это на самом деле не рекомендуется - docs.oracle.com/javase/8/docs/api/java/util/stream/… См. Раздел «Побочные эффекты». > Побочные эффекты в поведенческих параметрах потоковых операций, как правило, не приветствуются, так как они часто могут привести к непреднамеренным нарушениям требования безгражданства, а также к другим угрозам безопасности потоков. Так что в этом случае лучше использовать Collectors.toList ()

Anton Balaniuc 14.03.2017 18:31

@AntonBalaniuc Вопрос в том, действительно ли это побочный эффект. В этот момент newList не наблюдается ни в каком другом потоке. Но вы правы, что этого, вероятно, не следует делать, если неизвестно, откуда взялось значение newList (например, если newList был передан в качестве параметра.

SpaceTrucker 11.07.2017 08:45

Мне любопытно; почему .forEach(newList::addAll); вместо .collect(Collectors.toList());?

11684 22.08.2017 13:16

@ 11684, потому что сборщик собирает List<List<Object>>. Вы можете иметь в виду что-то вроде этого: stackoverflow.com/questions/189559/…

SpaceTrucker 22.08.2017 14:23

@SpaceTrucker Ой, я не заметил этого. Спасибо, что разъяснили мою путаницу. Да, мне следовало подумать о flatMap.

11684 22.08.2017 14:26

Java 8 (Stream.of and Stream.concat)

Предлагаемое решение предназначено для трех списков, хотя его можно применить и для двух списков. В Java 8 мы можем использовать Stream.of или Stream.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 принимает в качестве входных данных два потока и создает лениво объединенный поток, элементы которого являются элементами первого потока, за которым следуют все элементы второго потока. Поскольку у нас есть три списка, мы использовали этот метод (Stream.concat) два раза.

Мы также можем написать служебный класс с методом, который принимает любое количество списков (используя varargs) и возвращает объединенный список как:

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

Тогда мы можем использовать этот метод как:

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

Вот подход с использованием потоков и java 8, если ваши списки имеют разные типы и вы хотите объединить их в список другого типа.

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

еще одно решение для лайнера с использованием потока Java8, поскольку решение flatMap уже опубликовано, вот решение без flatMap

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

или же

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

код

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

выход

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

Я бы добавил, что это решение, вероятно, более производительно, чем то, которое использует flatMap, потому что списки повторяются только один раз, когда они собираются.

Stefan Haberl 23.05.2017 12:01

Версия Java 8 с поддержкой присоединения по ключу объекта:

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

В Java 8 (наоборот):

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

Этот подход уже предлагается в этом ответе: stackoverflow.com/a/37386846

Miles 24.03.2017 06:20

Если вы хотите сделать это статически, вы можете сделать следующее.

В примерах используются 2 набора EnumSet в естественном порядке (== порядок перечислений) A, B и затем объединяются в список 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);
                  }}
              );

Это создаст новый анонимный класс. Не рекомендуемый подход!

kravemir 25.01.2019 13:00

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

Вы можете создать свой общий служебный метод Java 8 для объединения любое количество списков.

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

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

}

Мы можем объединить 2 списка с помощью java8 с двумя подходами.

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

1) Использование concat:

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

2) Использование flatMap:

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

Отвечая на вопрос одиннадцатилетней давности тридцатью другими ответами, обязательно укажите, какие новые аспекты вопроса затрагивает ваш ответ, и отметьте, сработали бы эти методы, когда был задан вопрос, или они зависят от функций, которые были заданы. введен с годами.

Jason Aller 25.03.2020 21:05

Почти из ответов предлагается использовать ArrayList.

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

Предпочитайте использовать LinkedList для эффективных операций добавления.

Добавление ArrayList амортизируется за O (1), но в худшем случае за O (n), поскольку размер массива необходимо изменить и скопировать. В то время как LinkedList add всегда является постоянным O (1).

больше информации https://stackoverflow.com/a/322742/311420

Другие вопросы по теме