Об’єднайте два (або більше) списки в один у C # .NET


246

Чи можливо конвертувати два чи більше списків в один список, у .NET, використовуючи C #?

Наприклад,

public static List<Product> GetAllProducts(int categoryId){ .... }
.
.
.
var productCollection1 = GetAllProducts(CategoryId1);
var productCollection2 = GetAllProducts(CategoryId2);
var productCollection3 = GetAllProducts(CategoryId3);

Ви хочете об'єднати productCollection1 2 і 3?

ти маєш на увазі об'єднання більше одного списку в один список?
Amr Badawy

Ваш приклад мене бентежить ... Ви шукаєте AddRange-Метод?
Боббі

Відповіді:


457

Ви можете використовувати LINQ Concatта ToListметоди:

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

Зауважте, що є більш ефективні способи зробити це - вищезазначене в основному буде проглядати всі записи, створюючи буфер динамічного розміру. Оскільки ви можете передбачити розмір для початку, вам не потрібен цей динамічний розмір ... так що ви можете використовувати:

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

( AddRangeпризначений ICollection<T>для підвищення ефективності.)

Я б не користувався таким підходом, якщо вам це справді не доведеться.


4
BTW, productCollection1.ForEach(p => allProducts.Add(p))ефективніше, ніж AddRange.
Марк Клімент

8
@MarcCliment: Це досить сміливе твердження про ковдру - особливо, як AddRangeце робиться для блокової копії з одного базового масиву в інший. Чи є у вас посилання на підтвердження цього?
Джон Скіт

4
@MarcCliment: Для одного, у ваших тестах ви не створюєте список з правильним кінцевим розміром - тоді як код у моїй відповіді так і є. Зробіть це, і тест 10000 * 10000 швидше використовувати AddRange, принаймні - хоча інші результати суперечать. (Ви також повинні змусити збирання сміття між тестами - і я заперечую, що дуже короткі тести є безглуздо маленькими.)
Джон Скіт

6
@MarcCliment: Який конкретний випадок? Який CLR? Яка архітектура процесора? На своїй машині я отримую суміш результатів. Ось чому я не люблю заявляти / приймати бланкетні заяви, такі як "BTW, productionCollection1.ForEach(...)ефективніше, ніж AddRange". Продуктивність дуже рідко так легко описана. Я буду здивований , що AddRange не бити його зручним , хоча - мені потрібно досліджувати , що далі.
Джон Скіт

15
Я оновив суть ( gist.github.com/mcliment/4690433 ) тестом на працездатність за допомогою BenchmarksDotNet і належним чином протестований, AddRangeє найкращим варіантом для швидкої сировини (приблизно в 4 рази і чим більше списків, тим краще зростання), як Джон навіювати.
Марк Клімент

41

Якщо припустити, що ви хочете перелік, що містить усі продукти для вказаної категорії-ідентифікаторів, ви можете розглянути ваш запит як проекцію з наступною операцією вирівнювання . Там є оператор LINQ , що робить це: SelectMany.

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

У C # 4 ви можете скоротити SelectMany до: .SelectMany(GetAllProducts)

Якщо у вас вже є списки, що представляють продукти для кожного Id, то , як зазначають інші, потрібне з'єднання .


8
Якщо ОП не потребує індивідуальних списків з будь-якої іншої причини, це чудове рішення.
Джон Скіт

2
Мав подібну проблему і збирався відмовитись та поставити запитання, коли я це знайшов. Це найкраща відповідь. Особливо, якщо в коді вже є ті категорії у списку чи масиві, що було вірно в моєму випадку.

22

ви можете комбінувати їх за допомогою LINQ:

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

але більш традиційний підхід використання List.AddRange()може бути і більш ефективним.





4

Я знаю, що це старе питання, я думав, що я можу просто додати свої 2 центи.

Якщо у вас є, List<Something>[]ви можете приєднатися до них, використовуючиAggregate

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

    return result;
}

Сподіваюсь, це допомагає.


2

Я вже коментував це, але я все ще думаю, що це вірний варіант, просто перевірте, чи у вашому оточенні краще одне чи інше рішення. У моєму конкретному випадку використання source.ForEach(p => dest.Add(p))працює краще, ніж класичне, AddRangeале я не досліджував, чому на низькому рівні.

Приклад коду можна побачити тут: https://gist.github.com/mcliment/4690433

Таким варіантом було б:

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

Перевірте, чи працює він для вас.

Відмова : Я не виступаю за таке рішення, я вважаю Concatнайбільш зрозумілим. Я щойно заявив - в моїй дискусії з Джоном - що в моїй машині цей випадок працює краще AddRange, але він говорить, маючи набагато більше знань, ніж я, що це не має сенсу. Є суть, якщо ви хочете порівняти.


Незалежно від вашої дискусії з Джоном Скітом у коментарях, я дуже віддаю перевагу чистоті, запропонованій запропонованим ним рішенням, це просто додає зайвої інтерпретації щодо наміру кодексу.
Вікс

1
Я думаю, що найбільш зрозумілий варіант - Concat як узагальнення AddRange, семантично більш правильне і не змінює список на місці, що робить його доступним. Дискусія з Джоном стосувалася продуктивності, а не чистоти.
Marc Climent

У мене є щось подібне: var allProducts = lstName.Concat(lstCMSID) .Concat(lstSpecialtyPhys) .ToList();це додає його до GridView, але як один стовпець. Я хотів би розділити їх на три окремі колонки.
Si8

2
// I would make it a little bit more simple

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

Таким чином, це багатовимірний Список, і .SelectMany () вирівняє його в IEnumerable of product, то після цього я використовую метод .ToList ().


2

Щоб об'єднати або об'єднати в списки в один список.

  • Є одне, що має бути правдою: тип обох списків буде рівним.

  • Наприклад : якщо у нас є список, stringми можемо додати ще один список до існуючого списку, який має список рядка типу, інакше ми не можемо.

Приклад :

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

   }
}

1

У спеціальному випадку: "Усі елементи List1 переходять до нового List2": (наприклад, список рядків)

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

У цьому випадку список2 генерується з усіма елементами зі списку1.



0

Коли у вас мало списку, але ви не знаєте, скільки саме, скористайтеся цим:

listsOfProducts містить кілька списків, заповнених об’єктами.

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

listsOfProducts.ForEach(q => q.ForEach(e => productListMerged.Add(e)));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.