Kết hợp hai danh sách với nhau


333

Nếu tôi có hai danh sách chuỗi loại (hoặc bất kỳ loại nào khác), cách nhanh chóng để tham gia hai danh sách là gì?

Thứ tự nên giữ nguyên. Các bản sao phải được loại bỏ (mặc dù mỗi mục trong cả hai liên kết là duy nhất). Tôi đã không tìm thấy nhiều về điều này khi googling và không muốn thực hiện bất kỳ giao diện .NET nào cho tốc độ phân phối.


5
Có vấn đề gì không? Bạn có muốn giữ lại bản sao?
Larsenal

Câu trả lời:


572

Bạn có thể thử:

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

a.AddRange(b);

Trang MSDN cho AddRange

Điều này bảo tồn thứ tự của các danh sách, nhưng nó không loại bỏ bất kỳ bản sao nào Unionsẽ làm.

Điều này không thay đổi danh sách a. Nếu bạn muốn giữ danh sách gốc thì bạn nên sử dụng Concat(như được chỉ ra trong các câu trả lời khác):

var newList = a.Concat(b);

Điều này trả về một IEnumerablemiễn alà không null.


27
Không ai thực sự đi vào khi sử dụng phương pháp nào. AddRange chỉnh sửa một danh sách tại chỗ, thêm danh sách thứ hai vào danh sách đó (như thể bạn đã gọi .Add (foo) một loạt các lần). Các phương thức mở rộng của Concat và Union không thay đổi danh sách ban đầu. Họ lười biếng xây dựng một IEnumerable mới và thậm chí sẽ không truy cập vào các thành viên danh sách ban đầu trừ khi cần thiết. Như đã lưu ý, Union loại bỏ các bản sao trong khi những cái khác thì không.
ShawnFumo

4
Có ai biết sự phức tạp của phương pháp này là gì không? (Thật xấu hổ khi Microsoft không cung cấp thông tin quan trọng này như một phần của MSDN của họ)
Jacob

2
Tôi khuyên bạn nên kiểm tra so sánh tốt này của ông về các phương pháp khác nhau. Cũng hiển thị một số phân tích hiệu suất của các tùy chọn khác nhau: Hợp nhất Bộ sưu tập
BogeyMan

Điều này hoạt động hoàn hảo. Đã sử dụng concat () trên hơn nửa triệu mặt hàng, mất vài phút. Cách tiếp cận này mất ít hơn 5 giây.
GreenFerret95

110

Cách với chi phí không gian ít nhất là sử dụng phương pháp mở rộng Concat.

var combined = list1.Concat(list2);

Nó tạo ra một thể hiện trong IEnumerable<T>đó sẽ liệt kê các phần tử của list1 và list2 theo thứ tự đó.


2
hãy nhớ để using System.Linq;có thể sử dụng Concat
tothemario

43

Các Liên minh phương pháp có thể đáp ứng nhu cầu của bạn. Bạn đã không xác định liệu thứ tự hoặc trùng lặp là quan trọng.

Lấy hai IEnumerables và thực hiện một liên minh như được thấy ở đây:

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

Một cái gì đó như thế này:

firstList.AddRange (secondList);

Hoặc, bạn có thể sử dụng phương thức mở rộng 'Liên minh' được xác định trong System.Linq. Với 'Liên minh', bạn cũng có thể chỉ định một bộ so sánh, có thể được sử dụng để chỉ định xem một mục có nên được kết hợp hay không.

Như thế này:

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

Tôi nghĩ nó hoạt động tốt. Như đã nói trước đây, Concat trả về một chuỗi mới và trong khi chuyển đổi kết quả thành Danh sách, nó thực hiện công việc một cách hoàn hảo. Chuyển đổi ngầm định đôi khi có thể thất bại khi sử dụng phương thức AddRange.


13

Nếu một số mục tồn tại trong cả hai danh sách bạn có thể sử dụng

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

7

Miễn là chúng cùng loại, thật đơn giản với 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 }

Tôi cũng thích nó. Rất đơn giản. Cảm ơn.
GurdeepS

Tôi thích điều này bởi vì nó không đột biến một trong hai danh sách.
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

Một cách, tôi chưa thấy đề cập đến có thể mạnh mẽ hơn một chút, đặc biệt nếu bạn muốn thay đổi từng yếu tố theo một cách nào đó (ví dụ: bạn muốn .Trim()tất cả các yếu tố.

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

1

Xem liên kết này

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

// Lấy sản phẩm từ cả hai mảng // không bao gồm các bản sao.

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

Hai tùy chọn tôi sử dụng là:

list1.AddRange(list2);

hoặc là

list1.Concat(list2);

Tuy nhiên, tôi nhận thấy rằng tôi đã sử dụng rằng khi sử dụng AddRangephương thức có hàm đệ quy, nó tự gọi nó rất thường xuyên, tôi đã nhận được SystemOutOfMemoryException vì đã đạt được số lượng kích thước tối đa.

(Tin nhắn Google đã dịch)
Kích thước mảng vượt quá phạm vi được hỗ trợ.

Sử dụng Concatgiải quyết vấn đề đó.


0

Tôi chỉ muốn kiểm tra cách Unionhoạt động với bộ so sánh mặc định trên các bộ sưu tập các đối tượng kiểu tham chiếu chồng chéo.

Đối tượng của tôi là:

class MyInt
{
    public int val;

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

Mã kiểm tra của tôi là:

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

Đầu ra là:

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

Vì vậy, mọi thứ hoạt động tốt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.