Gabungkan dua (atau lebih) daftar menjadi satu, dalam C # .NET

246

Apakah mungkin untuk mengubah dua atau lebih daftar menjadi satu daftar tunggal, dalam .NET menggunakan C #?

Sebagai contoh,

public static List<Product> GetAllProducts(int categoryId){ .... }
.
.
.
var productCollection1 = GetAllProducts(CategoryId1);
var productCollection2 = GetAllProducts(CategoryId2);
var productCollection3 = GetAllProducts(CategoryId3);
zekia
sumber
Apakah Anda ingin menggabungkan productCollection1 2 dan 3?
maksud Anda menggabungkan lebih dari satu daftar dalam satu daftar?
Amr Badawy
Contoh Anda membingungkan saya ... apakah Anda mencari AddRange-Metode?
Bobby

Jawaban:

457

Anda dapat menggunakan LINQ Concatdan ToListmetode:

var allProducts = productCollection1.Concat(productCollection2)
                                    .Concat(productCollection3)
                                    .ToList();

Perhatikan bahwa ada cara yang lebih efisien untuk melakukan ini - yang di atas pada dasarnya akan melewati semua entri, membuat buffer berukuran dinamis. Karena Anda dapat memprediksi ukuran untuk memulai, Anda tidak perlu ukuran dinamis ini ... sehingga Anda dapat menggunakan:

var allProducts = new List<Product>(productCollection1.Count +
                                    productCollection2.Count +
                                    productCollection3.Count);
allProducts.AddRange(productCollection1);
allProducts.AddRange(productCollection2);
allProducts.AddRange(productCollection3);

( AddRangedikurung khusus ICollection<T>untuk efisiensi.)

Saya tidak akan mengambil pendekatan ini kecuali Anda benar-benar harus melakukannya.

Jon Skeet
sumber
4
BTW, productCollection1.ForEach(p => allProducts.Add(p))lebih berkinerja daripada AddRange.
Marc Climent
8
@MarcCliment: Itu pernyataan selimut yang cukup berani - terutama karena AddRangeakan melakukan copy blok dari satu array yang mendasarinya. Apakah Anda memiliki tautan untuk bukti ini?
Jon Skeet
4
@ MarcCliment: Yah untuk satu hal, dalam tes Anda, Anda tidak membuat daftar dengan ukuran akhir yang benar - sedangkan kode dalam jawaban saya tidak. Lakukan itu, dan tes 10.000 * 10.000 lebih cepat menggunakan AddRange, setidaknya - meskipun hasil lainnya tidak konsisten. (Anda juga harus memaksa pengumpulan sampah di antara tes - dan saya berpendapat bahwa tes yang sangat singkat tidak berarti.)
Jon Skeet
6
@MarcCliment: Kasus khusus apa? CLR yang mana? Arsitektur CPU yang mana? Di mesin saya, saya mendapatkan campuran hasil. Inilah sebabnya saya enggan menyatakan / menerima pernyataan selimut seperti "BTW, productionCollection1.ForEach(...)lebih berkinerja daripada AddRange". Performa sangat jarang sehingga mudah digambarkan. Aku sedang terkejut bahwa AddRange tidak pemukulan itu dgn mudah meskipun - saya perlu untuk menyelidiki yang lebih lanjut.
Jon Skeet
15
Saya telah memperbarui intisari ( gist.github.com/mcliment/4690433 ) dengan tes kinerja menggunakan BenchmarksDotNet dan telah diuji dengan benar, AddRangemerupakan pilihan terbaik untuk kecepatan mentah (sekitar 4x dan semakin besar daftar semakin baik peningkatan), seperti Jon sugesti.
Marc Climent
41

Dengan asumsi Anda menginginkan daftar yang berisi semua produk untuk kategori-Id yang ditentukan, Anda dapat memperlakukan kueri Anda sebagai proyeksi diikuti oleh operasi perataan . Ada operator LINQ yang melakukan itu: SelectMany.

// implicitly List<Product>
var products = new[] { CategoryId1, CategoryId2, CategoryId3 }
                     .SelectMany(id => GetAllProducts(id))
                     .ToList();

Di C # 4, Anda dapat mempersingkat SelectMany ke: .SelectMany(GetAllProducts)

Jika Anda sudah memiliki daftar yang mewakili produk untuk setiap Id, maka yang Anda butuhkan adalah gabungan , seperti yang ditunjukkan orang lain.

Ani
sumber
8
Jika OP tidak memerlukan daftar individual untuk alasan lain, ini adalah solusi yang bagus.
Jon Skeet
2
Memiliki masalah yang sama dan akan menyerah dan mengirim pertanyaan, ketika saya menemukan ini. Ini jawaban terbaik. Terutama jika kodenya sudah memiliki kategori tersebut dalam daftar atau array, yang benar dalam kasus saya.
22

Anda bisa menggabungkannya menggunakan LINQ:

  list = list1.Concat(list2).Concat(list3).ToList();

pendekatan penggunaan yang lebih tradisional List.AddRange()mungkin lebih efisien.

Botz3000
sumber
11

Lihat List.AddRange untuk menggabungkan Daftar

StuartLC
sumber
8

Anda dapat menggunakan metode ekstensi Concat :

var result = productCollection1
    .Concat(productCollection2)
    .Concat(productCollection3)
    .ToList();
Darin Dimitrov
sumber
8
list4 = list1.Concat(list2).Concat(list3).ToList();
decyclone
sumber
4

Saya tahu ini adalah pertanyaan lama yang saya pikir mungkin saya tambahkan 2 sen saja.

Jika sudah punya, List<Something>[]Anda bisa bergabung dengan mereka menggunakanAggregate

public List<TType> Concat<TType>(params List<TType>[] lists)
{
    var result = lists.Aggregate(new List<TType>(), (x, y) => x.Concat(y).ToList());

    return result;
}

Semoga ini membantu.

sQuir3l
sumber
2

Saya sudah berkomentar tapi saya masih berpikir itu pilihan yang valid, hanya menguji apakah di lingkungan Anda lebih baik satu solusi atau yang lain. Dalam kasus khusus saya, menggunakan source.ForEach(p => dest.Add(p))berkinerja lebih baik daripada yang klasik AddRangetapi saya belum menyelidiki mengapa di level rendah.

Anda dapat melihat contoh kode di sini: https://gist.github.com/mcliment/4690433

Jadi opsinya adalah:

var allProducts = new List<Product>(productCollection1.Count +
                                    productCollection2.Count +
                                    productCollection3.Count);

productCollection1.ForEach(p => allProducts.Add(p));
productCollection2.ForEach(p => allProducts.Add(p));
productCollection3.ForEach(p => allProducts.Add(p));

Uji untuk mengetahui apakah itu cocok untuk Anda.

Penafian : Saya tidak menganjurkan solusi ini, saya menemukan Concatyang paling jelas. Saya baru saja menyatakan - dalam diskusi saya dengan Jon - bahwa di mesin saya kasus ini berkinerja lebih baik daripada AddRange, tetapi dia mengatakan, dengan pengetahuan yang jauh lebih banyak daripada saya, bahwa ini tidak masuk akal. Ada intinya jika Anda ingin membandingkan.

Marc Climent
sumber
Terlepas dari perdebatan Anda dengan Jon Skeet di komentar, saya lebih suka kebersihan yang ditawarkan oleh solusi yang diusulkannya, ini hanya menambah interpretasi yang tidak perlu mengenai maksud kode.
Vix
1
Saya pikir opsi yang paling jelas adalah Concat sebagai generalisasi dari AddRange, secara semantik lebih benar dan tidak mengubah daftar di tempat yang membuatnya dapat ditransfer. Diskusi dengan Jon adalah tentang kinerja, bukan kebersihan.
Marc Climent
Saya memiliki sesuatu seperti ini: var allProducts = lstName.Concat(lstCMSID) .Concat(lstSpecialtyPhys) .ToList();yang menambahkannya ke GridView tetapi sebagai satu kolom. Saya ingin membaginya menjadi tiga kolom terpisah.
Si8
2
// I would make it a little bit more simple

 var products = new List<List<product>> {item1, item2, item3 }.SelectMany(id => id).ToList();

Dengan cara ini adalah Daftar multi dimensi dan .SelectMany () akan meratakannya menjadi produk IEnumerable maka saya menggunakan metode .ToList () setelahnya.

Gringo Jaimes
sumber
2

Untuk menggabungkan atau Menggabungkan ke Daftar ke dalam daftar Satu.

  • Ada satu hal yang pasti benar: jenis kedua daftar akan sama.

  • Sebagai Contoh : jika kita memiliki daftar stringsehingga kita dapat menambahkan tambahkan daftar lain ke daftar yang ada yang memiliki daftar tipe string kalau tidak kita tidak bisa.

Contoh :

class Program
{
   static void Main(string[] args)
   {
      List<string> CustomerList_One = new List<string> 
      {
         "James",
         "Scott",
         "Mark",
         "John",
         "Sara",
         "Mary",
         "William",
         "Broad",
         "Ben",
         "Rich",
         "Hack",
         "Bob"
      };

      List<string> CustomerList_Two = new List<string> 
      {
         "Perter",
         "Parker",
         "Bond",
         "been",
         "Bilbo",
         "Cooper"
      };

      // Adding all contents of CustomerList_Two to CustomerList_One.
      CustomerList_One.AddRange(CustomerList_Two);

      // Creating another Listlist and assigning all Contents of CustomerList_One.
      List<string> AllCustomers = new List<string>();

      foreach (var item in CustomerList_One)
      {
         AllCustomers.Add(item);
      }

      // Removing CustomerList_One & CustomerList_Two.
      CustomerList_One = null;

      CustomerList_Two = null;
      // CustomerList_One & CustomerList_Two -- (Garbage Collected)
      GC.Collect();

      Console.WriteLine("Total No. of Customers : " +  AllCustomers.Count());
      Console.WriteLine("-------------------------------------------------");
      foreach (var customer in AllCustomers)
      {
         Console.WriteLine("Customer : " + customer);
      }
      Console.WriteLine("-------------------------------------------------");

   }
}
Rehan Shah
sumber
1

Dalam kasus khusus: "Semua elemen List1 menuju ke List2 baru": (mis. Daftar string)

List<string> list2 = new List<string>(list1);

Dalam hal ini, list2 dihasilkan dengan semua elemen dari list1.

Arthur Zennig
sumber
0

Anda perlu menggunakan operasi Concat

Artem
sumber
0

Ketika Anda memiliki beberapa daftar tetapi Anda tidak tahu berapa tepatnya, gunakan ini:

listsOfProducts berisi beberapa daftar berisi objek.

List<Product> productListMerged = new List<Product>();

listsOfProducts.ForEach(q => q.ForEach(e => productListMerged.Add(e)));
john.kernel
sumber