如何在Java中加入两个列表?

Rob*_*ins 694 java list jdk1.5

条件:不修改原始列表; 仅限JDK,没有外部库.单行或JDK 1.3版本的奖励积分.

有没有比以下更简单的方法:

List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);
Run Code Online (Sandbox Code Playgroud)

Ada*_*amC 543

在我的头顶,我可以缩短一行:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
Run Code Online (Sandbox Code Playgroud)

  • 虽然你在技术上是正确的,但你已经将它缩短了一行,这种不对称性使我感到不安.够了,我更乐意"花"额外的路线. (145认同)
  • 这里有没有问题,newList的interal数组将初始化为listOne的大小,然后在添加listTwo的所有项目时必须扩展?获取每个列表的大小并使用它来调整新数组的大小会更好吗? (13认同)
  • 这是最适合我的解决方案.我对不同解决方案的性能进行了比较,这些解决方案获得了胜利,同时创建了空列表,然后创建了两个`addAll()`.我尝试了所有那些建议不复制列表的人,结果我们这次不需要很多开销. (2认同)

Dal*_*ery 523

在Java 8中:

List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
                             .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • Gawd,这是Java 8中的一个东西吗?从技术上讲,你我赢了,但这是一个很长的路线:-) (65认同)
  • concat 的替代方案:流流 `Stream.of(listOne, listTwo).flatMap(Collection::stream).collect(Collectors.toList())` (9认同)
  • 它很丑,但至少它流畅,可以在没有多线lambda的情况下使用.我真的希望有一个流畅的addAll返回到concatinated列表. (7认同)
  • 对于休闲读者来说,这是一个使用Java _ St​​reams的更短的解决方案:http://stackoverflow.com/a/34090554/363573 (4认同)
  • 我想值得注意的是,从中也可以很容易地得到一个独特的列表,就像这样:`List &lt;String&gt; newList = Stream.concat(listOne.stream(),listTwo.stream())。distinct()。 collect(Collectors.toList());` (4认同)

小智 276

您可以使用Apache commons-collections库:

List<String> newList = ListUtils.union(list1, list2);
Run Code Online (Sandbox Code Playgroud)

  • @Quantum7,对其他人仍然有用;)另外,apache公共甚至是外部库吗?没有它,我什么都没开始! (95认同)
  • 很好,但需要apache公共.他指的是"没有外部图书馆" (49认同)
  • @Platinum不,根据文档ListUtils.union完全等同于OP的代码.但也许在列表上下文中使用SET操作("Union")会产生误导.我可以看到你如何期望这可以删除重复或类似的东西,但似乎该方法不会这样做. (28认同)
  • 避免使用Apache Commons Collections.它不是类型安全的,没有泛型.如果你使用Java 1.4很好,但对于Java 5及更高版本,我更喜欢Google Guava. (24认同)
  • @MichaelPiefel最新的Apache Commons Collections 4是类型安全的.使用Java 8方法引用,这种静态实用程序变得非常重要. (9认同)
  • @Richard是的,但是`Iterables.concat()`怎么样?大多数时候它正是你想要的.如果您绝对需要新列表,请使用`Lists.newArrayList(Iterables.concat(...))`. (3认同)
  • 赞成,因为这是唯一不需要多个方法调用的答案。流很有趣,但必须为每个...单个...小....事情...做n个方法调用似乎容易出错。加入两个列表应该是一个简单的操作。 (2认同)
  • 不幸的是,ListUtils.union() 不支持超过 2 个参数 (2认同)

Kev*_*n K 85

您的一个要求是保留原始列表.如果创建新列表并使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);
Run Code Online (Sandbox Code Playgroud)

  • 这是这个问题的真正答案. (12认同)
  • 这是一个可行的解决方案,但请注意,如果基础列表对象发生更改(list1,list2),则此列表的内容会发生变化.您可能无法修改CompositeUnmodifiableList _itself_的实例,但如果您可以获得对原始列表的引用,则可以.对于那些不熟悉的人:最终修饰符只影响_reference_到列表对象本身不能改变但是列表内容仍然可以改变! (8认同)
  • @jwj都非常好点,谢谢.类名可能值得一些解释.我认为这个类与`Collections.unmodifiableList()`方法非常相似,它包装了一个列表以使其不可修改.`CompositeUnmodifiableList`做同样的事情,除了它包装两个列表并提供连接的视图.关于`CompositeUnmodifiableList`的所有要点也适用于`Collections.unmodifiableList()`. (3认同)
  • 构造函数可以采用`List&lt;? 扩展 E&gt;` (2认同)

vol*_*ley 84

可能不简单,但有趣和丑陋:

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };
Run Code Online (Sandbox Code Playgroud)

不要在生产代码中使用它...;)

  • 丑陋和邪恶,就像几乎任何使用双括号初始化一样.但它更短;) (42认同)
  • 虽然它实际上是一条线,但我不认为这是"单线". (20认同)
  • @NimChimpsky我认为这主要是因为它不仅仅是一个匿名块初始化器,而是你实际上正在创建一个ArrayList的匿名子类.话虽这么说,如果你相信这个[Double Brace Initilization question](http://stackoverflow.com/questions/924285/efficiency-of-java-double-brace-initialization)的结果,它会让人觉得讨厌DBI主要是风格品味和微观优化.据我所知,这样做没有重大的惩罚.如果你试图比较它的类,那么偷偷摸摸的缺点就是因为它不是ArrayList. (18认同)
  • 为什么人们讨厌匿名块初始化器 (11认同)
  • @MarnixKlooster:Eclipse*知道*你不应该使用它并使它使用起来不愉快;-) (4认同)
  • 如何使用双支撑初始化使其成为单线程? (2认同)
  • @NimChimpsky 您可以查看这篇关于双花括号初始化缺点的文章:[不要“聪明”:双花括号反模式](https://blog.jooq.org/2014/12/08/dont -be-clever-the-double-curly-braces-anti-pattern/) (2认同)

Mar*_*tin 70

不简单,但没有调整开销:

List<String> newList = new ArrayList<>(listOne.size() + listTwo.size());
newList.addAll(listOne);
newList.addAll(listTwo);
Run Code Online (Sandbox Code Playgroud)


Mar*_*ark 67

另一个Java 8单线程:

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

作为奖励,因为Stream.of()是可变参数,您可以根据需要连接多个列表.

List<String> newList = Stream.of(listOne, listTwo, listThree)
                             .flatMap(x -> x.stream())
                             .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • `x - > x.stream()`可以替换为`Collection :: stream`. (31认同)
  • ......甚至是`List :: stream`. (7认同)
  • 在 JDK 17 中,`.collect(Collectors.toList())` 可以仅替换为 `.toList()`; (3认同)

Yur*_*ish 51

发现这个问题寻找连接任意数量的列表,而不是关注外部库.所以,也许它会帮助别人:

com.google.common.collect.Iterables#concat()
Run Code Online (Sandbox Code Playgroud)

如果要将相同的逻辑应用于for()中的多个不同集合,则非常有用.

  • 例如:Lists.newArrayList(Iterables.concat(list1,list2)); (8认同)

Spa*_*ker 38

这是一个使用两行的java 8解决方案:

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

请注意,如果使用此方法,则不应使用此方法

  • 原因newList尚不清楚,可能已经与其他线程共享
  • 修改的流newList是并行流,并且访问 newList不同步或线程安全

由于副作用的考虑.

上述两个条件都不适用于上述加入两个列表的情况,因此这是安全的.

基于这个答案的另一个问题.

  • 如果我没有错,实际上不建议这样做 - docs.oracle.com/javase/8/docs/api/java/util/stream/...请参阅side -effects部分.>一般来说,不鼓励行为参数对流操作的副作用,因为它们通常会导致无意中违反无国籍要求,以及其他线程安全危险.所以在这种情况下最好使用Collectors.toList() (11认同)
  • @ 11684因为收集器会收集一个`List <List <Object >>.您可能想到的是这样的:/sf/ask/13269161/#37386846 (4认同)
  • 我很好奇; 为什么`.forEach(newList::addAll);` 而不是`.collect(Collectors.toList());`? (2认同)

i_a*_*ero 34

建议的解决方案适用于三个列表,但它也可以应用于两个列表.在Java 8中,我们可以使用Stream.ofStream.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());
Run Code Online (Sandbox Code Playgroud)

Stream.concat将两个流作为输入并创建一个延迟连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素.由于我们有三个列表,我们使用了这个方法(Stream.concat)两次.

我们还可以使用一个方法编写一个实用程序类,该方法可以获取任意数量的列表(使用varargs)并返回一个连接列表:

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

然后我们可以使用这个方法:

List<String> result3 = Utils.concatenateLists(list1,list2,list3);
Run Code Online (Sandbox Code Playgroud)


cek*_*ock 32

这很简单,只有一行,但会将listTwo的内容添加到listOne.你真的需要将内容放在第三个列表中吗?

Collections.addAll(listOne, listTwo.toArray());
Run Code Online (Sandbox Code Playgroud)

  • 不修改原始列表是其中一个标准,但这对于此处作为不是约束的情况的示例很有用. (9认同)
  • 谢谢,或者更简单的 listOne.addAll(listTwo) (5认同)

Tim*_*Tim 26

稍微简单一些:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
Run Code Online (Sandbox Code Playgroud)

  • @Zainodis是的,可能有重复.`List`结构没有强加唯一性约束.您可以通过使用集合执行相同的操作来删除欺骗.`Set <String> newSet = new HashSet <>(setOne); newSet.addAll(setTwo);` (4认同)

Jor*_*orn 20

稍短一点就是:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
Run Code Online (Sandbox Code Playgroud)


Dan*_*ári 14

您可以创建通用Java 8实用程序方法来连接任意数量的列表.

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


det*_*erb 13

如果目标列表是预先声明的,则可以执行oneliner.

(newList = new ArrayList<String>(list1)).addAll(list2);
Run Code Online (Sandbox Code Playgroud)


Nit*_*ain 9

Java 8中(另一种方式):

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


小智 9

我们可以通过 2 种方法使用 java8 连接 2 个列表。

    List<String> list1 = Arrays.asList("S", "T");
    List<String> list2 = Arrays.asList("U", "V");
Run Code Online (Sandbox Code Playgroud)

1) 使用 concat :

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

2)使用 flatMap :

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

  • 当回答一个十一年前的问题和三十个其他答案时,一定要指出你的答案解决了问题的哪些新方面,并注意这些技术在提出问题时是否有效,或者它们是否依赖于已经被解决的功能。多年来推出。 (3认同)

Sar*_*ana 8

使用Java8流的另一个线性解决方案,因为flatMap已经发布了解决方案,这里是一个没有的解决方案flatMap

List<E> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);
Run Code Online (Sandbox Code Playgroud)

要么

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

    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);
Run Code Online (Sandbox Code Playgroud)

产量

[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)


Ray*_*non 8

几乎所有的答案都建议使用 ArrayList。

List<String> newList = new LinkedList<>(listOne);
newList.addAll(listTwo);
Run Code Online (Sandbox Code Playgroud)

更喜欢使用 LinkedList 进行高效的添加操作。

ArrayList add 是 O(1) 摊销,但 O(n) 最坏情况,因为必须调整数组大小和复制。而 LinkedList add 总是常数 O(1)。

更多信息/sf/answers/22591971/

  • 如果没有性能基准,这是一个值得怀疑的建议,特别是因为您关于“add”的争论并不涉及批量“addAll”操作。 (3认同)

Oli*_*eux 6

我认为最聪明的是:

/**
 * @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;
}
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记`@SafeVarargs`! (3认同)

Dav*_*ney 5

您可以使用静态导入和帮助程序类来完成此操作

注意这个类的generification很可能得到改善

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

}
Run Code Online (Sandbox Code Playgroud)

然后你可以做的事情

import static Lists.join;
List<T> result = join(list1, list2, list3, list4);
Run Code Online (Sandbox Code Playgroud)


小智 5

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());
}
Run Code Online (Sandbox Code Playgroud)