将两个列表结合在一起


333

如果我有两个类型为字符串(或任何其他类型)的列表,联接两个列表的快速方法是什么?

顺序应保持不变。应该删除重复项(尽管两个链接中的每个项目都是唯一的)。在Google上进行搜索时,我发现的内容并不多,也不想实现任何.NET接口来提高交付速度。


5
顺序重要吗?您要保留重复项吗?
拉森纳尔

Answers:


573

您可以尝试:

List<string> a = new List<string>();
List<string> b = new List<string>();

a.AddRange(b);

的MSDN页面 AddRange

这样可以保留列表的顺序,但是不会删除任何重复的列表Union

这确实会更改列表a。如果要保留原始列表,则应使用Concat(如其他答案中所指出的):

var newList = a.Concat(b);

IEnumerable只要a不为null ,则返回a 。


27
没有人真正了解何时使用哪种方法。AddRange在适当的位置编辑列表,向其中添加第二个列表(就像您多次调用.Add(foo)一样)。Concat和Union扩展方法不会更改原始列表。他们懒洋洋地构造了一个新的IEnumerable,除非有必要,他们甚至都不会访问原始列表成员。如前所述,Union删除重复项,而其他不删除。
ShawnFumo 2015年

4
有谁知道这种方法的复杂性?(真可惜,微软没有在MSDN中提供这些重要信息)
Jacob 2016年

2
我建议您检查一下他对各种方法的良好比较。还显示了各种选项的性能分析:合并集合
BogeyMan

这很完美。在超过500万个项目上使用了concat(),这花了几分钟。这种方法不到5秒。
GreenFerret95

111

占用空间最少的方法是使用Concat扩展方法。

var combined = list1.Concat(list2);

它创建一个实例,IEnumerable<T>该实例将按此顺序枚举list1和list2的元素。


2
记住using System.Linq;要能够使用Concat
tothemario '19

43

联盟的方法可能会满足您的需求。您没有指定顺序还是重复很重要。

取两个IEnumerables并执行一个联合,如下所示:

int[] ints1 = { 5, 3, 9, 7, 5, 9, 3, 7 };
int[] ints2 = { 8, 3, 6, 4, 4, 9, 1, 0 };

IEnumerable<int> union = ints1.Union(ints2);

// yields { 5, 3, 9, 7, 8, 6, 4, 1, 0 } 

24

像这样:

firstList.AddRange (secondList);

或者,您可以使用System.Linq中定义的“ Union”扩展方法。使用“联合”,您还可以指定一个比较器,该比较器可用于指定是否应合并项目。

像这样:

List<int> one = new List<int> { 1, 2, 3, 4, 5 };
List<int> second=new List<int> { 1, 2, 5, 6 };

var result = one.Union (second, new EqComparer ());

foreach( int x in result )
{
    Console.WriteLine (x);
}
Console.ReadLine ();

#region IEqualityComparer<int> Members
public class EqComparer : IEqualityComparer<int>
{
    public bool Equals( int x, int y )
    {
        return x == y;
    }

    public int GetHashCode( int obj )
    {
        return obj.GetHashCode ();
    }
}
#endregion

17
targetList = list1.Concat(list2).ToList();

我认为效果很好。如前所述,Concat返回一个新序列,并将结果转换为List时,它可以完美地完成工作。使用AddRange方法时,隐式转换有时可能会失败。


13

如果两个列表中都有某些项目,则可以使用

var all = list1.Concat(list2).Concat(list3) ... Concat(listN).Distinct().ToList();

7

只要它们是相同的类型,使用AddRange就非常简单:

list2.AddRange(list1);

7
var bigList = new List<int> { 1, 2, 3 }
    .Concat(new List<int> { 4, 5, 6 })
    .ToList(); /// yields { 1, 2, 3, 4, 5, 6 }

我也喜欢 很简单。谢谢。
GurdeepS

我喜欢这个,因为它不会改变任何一个列表。
Ev。


4
List<string> list1 = new List<string>();
list1.Add("dot");
list1.Add("net");

List<string> list2 = new List<string>();
list2.Add("pearls");
list2.Add("!");

var result = list1.Concat(list2);


2

一种方法,我没有看到它可以更健壮,特别是如果您想以某种方式更改每个元素(例如,想要对.Trim()所有元素进行更改)。

List<string> a = new List<string>();
List<string> b = new List<string>();
// ...
b.ForEach(x=>a.Add(x.Trim()));

1

看到这个链接

public class ProductA
{ 
public string Name { get; set; }
public int Code { get; set; }
}

public class ProductComparer : IEqualityComparer<ProductA>
{

public bool Equals(ProductA x, ProductA y)
{
    //Check whether the objects are the same object. 
    if (Object.ReferenceEquals(x, y)) return true;

    //Check whether the products' properties are equal. 
    return x != null && y != null && x.Code.Equals(y.Code) && x.Name.Equals(y.Name);
    }

public int GetHashCode(ProductA obj)
{
    //Get hash code for the Name field if it is not null. 
    int hashProductName = obj.Name == null ? 0 : obj.Name.GetHashCode();

    //Get hash code for the Code field. 
    int hashProductCode = obj.Code.GetHashCode();

    //Calculate the hash code for the product. 
    return hashProductName ^ hashProductCode;
}
}


    ProductA[] store1 = { new ProductA { Name = "apple", Code = 9 }, 
                   new ProductA { Name = "orange", Code = 4 } };

    ProductA[] store2 = { new ProductA { Name = "apple", Code = 9 }, 
                   new ProductA { Name = "lemon", Code = 12 } };

//从两个数组中获取产品//不包括重复项。

IEnumerable<ProductA> union =
  store1.Union(store2);

foreach (var product in union)
    Console.WriteLine(product.Name + " " + product.Code);

/*
    This code produces the following output:

    apple 9
    orange 4
    lemon 12
*/

1

我使用的两个选项是:

list1.AddRange(list2);

要么

list1.Concat(list2);

但是,我注意到,当我使用AddRange带有递归函数的方法时,由于经常达到最大尺寸数,因此我经常调用自身,而出现SystemOutOfMemoryException异常。

(消息Google翻译)
数组尺寸超出了支持的范围。

使用Concat解决了这个问题。


0

我只想测试Union在引用类型对象的重叠集合上使用默认比较器的方式。

我的对象是:

class MyInt
{
    public int val;

    public override string ToString()
    {
        return val.ToString();
    }
}

我的测试代码是:

MyInt[] myInts1 = new MyInt[10];
MyInt[] myInts2 = new MyInt[10];
int overlapFrom = 4;
Console.WriteLine("overlapFrom: {0}", overlapFrom);

Action<IEnumerable<MyInt>, string> printMyInts = (myInts, myIntsName) => Console.WriteLine("{2} ({0}): {1}", myInts.Count(), string.Join(" ", myInts), myIntsName);

for (int i = 0; i < myInts1.Length; i++)
    myInts1[i] = new MyInt { val = i };
printMyInts(myInts1, nameof(myInts1));

int j = 0;
for (; j + overlapFrom < myInts1.Length; j++)
    myInts2[j] = myInts1[j + overlapFrom];
for (; j < myInts2.Length; j++)
    myInts2[j] = new MyInt { val = j + overlapFrom };
printMyInts(myInts2, nameof(myInts2));

IEnumerable<MyInt> myUnion = myInts1.Union(myInts2);
printMyInts(myUnion, nameof(myUnion));

for (int i = 0; i < myInts2.Length; i++)
    myInts2[i].val += 10;
printMyInts(myInts2, nameof(myInts2));
printMyInts(myUnion, nameof(myUnion));

for (int i = 0; i < myInts1.Length; i++)
    myInts1[i].val = i;
printMyInts(myInts1, nameof(myInts1));
printMyInts(myUnion, nameof(myUnion));

输出为:

overlapFrom: 4
myInts1 (10): 0 1 2 3 4 5 6 7 8 9
myInts2 (10): 4 5 6 7 8 9 10 11 12 13
myUnion (14): 0 1 2 3 4 5 6 7 8 9 10 11 12 13
myInts2 (10): 14 15 16 17 18 19 20 21 22 23
myUnion (14): 0 1 2 3 14 15 16 17 18 19 20 21 22 23
myInts1 (10): 0 1 2 3 4 5 6 7 8 9
myUnion (14): 0 1 2 3 4 5 6 7 8 9 20 21 22 23

因此,一切正常。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.