Bergabung dengan dua daftar bersama


333

Jika saya memiliki dua daftar tipe string (atau tipe lain), apa cara cepat untuk bergabung dengan dua daftar?

Pesanan harus tetap sama. Duplikat harus dihapus (meskipun setiap item di kedua tautan unik). Saya tidak menemukan banyak tentang ini ketika googling dan tidak ingin mengimplementasikan antarmuka .NET untuk kecepatan pengiriman.


5
Apakah pesanan itu penting? Apakah Anda ingin menyimpan duplikat?
Larsenal

Jawaban:


574

Kamu bisa mencoba:

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

a.AddRange(b);

Halaman MSDN untuk AddRange

Ini mempertahankan urutan daftar, tetapi tidak menghapus duplikat mana pun Union akan dilakukan.

Ini memang mengubah daftar a. Jika Anda ingin menyimpan daftar asli maka Anda harus menggunakan Concat(sebagaimana ditunjukkan dalam jawaban lain):

var newList = a.Concat(b);

Ini mengembalikan IEnumerableselama atidak nol.


27
Tidak ada yang benar-benar tertarik ketika menggunakan metode mana. AddRange mengedit daftar di tempat, menambahkan daftar kedua ke dalamnya (seolah-olah Anda memanggil. Tambahkan (foo) beberapa kali). Metode ekstensi Concat dan Union tidak mengubah daftar asli. Mereka dengan malas membuat IEnumerable baru dan bahkan tidak akan mengakses anggota daftar asli kecuali diperlukan. Seperti dicatat, Union menghapus duplikat sementara yang lain tidak.
ShawnFumo

4
Adakah yang tahu kerumitan metode ini? (Sayang sekali Microsoft tidak menyediakan informasi penting ini sebagai bagian dari MSDN mereka)
Yakub

2
Saya sarankan Anda memeriksa perbandingan yang baik ini dari berbagai pendekatan. Juga menunjukkan beberapa analisis kinerja dari berbagai opsi: Gabungkan Koleksi
BogeyMan

Ini bekerja dengan sempurna. Sedang menggunakan concat () pada lebih dari setengah juta item, yang membutuhkan waktu beberapa menit. Pendekatan ini membutuhkan waktu kurang dari 5 detik.
GreenFerret95

111

Cara dengan overhead ruang terkecil adalah dengan menggunakan metode ekstensi Concat.

var combined = list1.Concat(list2);

Itu menciptakan sebuah instance IEnumerable<T>yang akan menyebutkan elemen-elemen dari list1 dan list2 dalam urutan itu.


2
ingatlah untuk using System.Linq;dapat menggunakan Concat
tothemario

43

The Union Metode mungkin memenuhi kebutuhan Anda. Anda tidak menentukan apakah pesanan atau duplikat penting.

Ambil dua IEnumerables dan lakukan penyatuan seperti yang terlihat di sini:

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

Sesuatu seperti ini:

firstList.AddRange (secondList);

Atau, Anda dapat menggunakan metode ekstensi 'Union' yang didefinisikan dalam System.Linq. Dengan 'Serikat', Anda juga dapat menentukan pembanding, yang dapat digunakan untuk menentukan apakah suatu barang harus disatukan atau tidak.

Seperti ini:

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

Saya pikir itu berfungsi dengan baik. Seperti yang dikatakan sebelumnya, Concat mengembalikan urutan baru dan saat mengubah hasilnya menjadi Daftar, ia melakukan pekerjaan dengan sempurna. Konversi tersirat terkadang gagal saat menggunakan metode AddRange.


13

Jika beberapa item ada di kedua daftar yang dapat Anda gunakan

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

7

Selama mereka memiliki tipe yang sama, itu sangat sederhana dengan 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 }

Saya juga suka ini. Sangat sederhana. Terima kasih.
GurdeepS

Saya suka ini karena tidak mengubah daftar mana pun.
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

Satu cara, saya belum melihat yang bisa sedikit lebih kuat, terutama jika Anda ingin mengubah setiap elemen dengan cara tertentu (misalnya Anda ingin .Trim()semua elemen.

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

1

Lihat tautan ini

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

// Dapatkan produk dari kedua array // tidak termasuk duplikat.

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

Dua opsi yang saya gunakan adalah:

list1.AddRange(list2);

atau

list1.Concat(list2);

Namun saya perhatikan ketika saya menggunakan itu ketika menggunakan AddRangemetode dengan fungsi rekursif, yang menyebut dirinya sangat sering saya mendapat SystemOutOfMemoryException karena jumlah maksimum dimensi tercapai.

(Pesan Google Diterjemahkan)
Dimensi array melebihi rentang yang didukung.

Menggunakan Concatmemecahkan masalah itu.


0

Saya hanya ingin menguji cara Unionkerjanya dengan pembanding default pada koleksi objek tipe tumpang tindih.

Objek saya adalah:

class MyInt
{
    public int val;

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

Kode pengujian saya adalah:

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

Outputnya adalah:

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

Jadi, semuanya bekerja dengan baik.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.