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

条件:不修改原始列表;仅限JDK,无外部库。单行或JDK 1.3版本的加分。

有没有比这更简单的方法:

List<String> newList = new ArrayList<String>();newList.addAll(listOne);newList.addAll(listTwo);
1272149 次浏览

稍微简单一点:

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

从我的头顶,我可以把它缩短一行:

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

稍微短一点的是:

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

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

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

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

如果目标列表已预先声明,则可以执行oneliner。

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

如果不介绍您自己的实用程序方法,我无法在一般情况下改进两行代码,但是如果您确实有字符串列表并且您愿意假设这些字符串不包含逗号,您可以提取这个长的一行代码:

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(尽管我还没有测试过)。也不推荐用于生产代码;-)

我不是说这很简单,但你提到了单行的奖金;-)

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

使用Helper类。

本人建议:

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

发现这个问题希望连接任意数量的列表,而不考虑外部库。所以,也许它会帮助其他人:

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

如果您想在一个for()中将相同的逻辑应用于多个不同的集合,则很有用。

没有办法接近一行,但我认为这是最简单的:

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

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

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<? 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;}    
@Overridepublic E get(int index) {if (index < list1.size()) {return list1.get(index);}return list2.get(index-list1.size());}
@Overridepublic int size() {return list1.size() + list2.size();}}

用法:

List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);
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"));
}
}

Java8:

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

Java16+:

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

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

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

另一个Java8:

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());
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的访问不同步或线程安全

由于副作用的考虑。

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

基于这个答案到另一个问题。

Java8(Stream.ofStream.concat

建议的解决方案是三个列表,尽管它也可以应用于两个列表。在Java8中,我们可以使用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());

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]

Java8版本,支持通过对象键加入:

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

Java8(另一种方式):

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

如果您想静态执行此操作,您可以执行以下操作。

示例在自然顺序(==枚举顺序)A, B中使用2个枚举集,然后连接到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);}});
public static <T> List<T> merge(@Nonnull final List<T>... list) {// calculate length firstint 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;}

您可以创建泛型Java8实用程序方法来concat任意数量的列表

@SafeVarargspublic 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;}
@Overridepublic E get(final int index) {return getList(index).get(getListIndex(index));}
@Overridepublic E set(final int index, final E element) {return getList(index).set(getListIndex(index), element);}
@Overridepublic void add(final int index, final E element) {getList(index).add(getListIndex(index), element);}
@Overridepublic E remove(final int index) {return getList(index).remove(getListIndex(index));}
@Overridepublic int size() {return list1.size() + list2.size();}
@Overridepublic boolean contains(final Object o) {return list1.contains(o) || list2.contains(o);}
@Overridepublic 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;}
}

我们可以使用java8和2种方法加入2个列表。

    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)使用platMap:

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

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

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

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

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

更多信息https://stackoverflow.com/a/322742/311420

我最喜欢的方式,使用流利的api和Guava:

List<String> combined = ImmutableList.<String>builder().addAll(list1).addAll(list2).build()