C#.NETで2つ(またはそれ以上)のリストを1つにマージする


246

C#を使用して.NETで2つ以上のリストを1つのリストに変換することは可能ですか?

例えば、

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

productCollection1 2と3をマージしますか?

1つのリストに複数のリストをマージするということですか?
Amr Badawy、2010

あなたの例は私を混乱させています...あなたは-メソッドを探していAddRangeますか?
Bobby

回答:


457

LINQ ConcatToListメソッドを使用できます。

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

AddRangeICollection<T>、効率のために特別なケースです。)

あなたが本当にしなければならない限り、私はこのアプローチをとらないでしょう。


4
ところで、productCollection1.ForEach(p => allProducts.Add(p))AddRangeよりもパフォーマンスが優れています。
Marc Climent 2013年

8
@MarcCliment:これはかなり大胆な包括的なステートメントです。特にAddRange、1つの基になる配列から別の配列へのブロックコピーを実行するためです。これを証明するリンクはありますか?
Jon Skeet 2013年

4
@MarcCliment:一つには、テストで正しい最終サイズのリストを作成していない -私の答えのコードはそうですが。そうすれば、少なくともAddRangeを使用すると、10000 * 10000テストの方が高速になります。ただし、他の結果には一貫性がありません。(テスト間でガベージコレクションを強制する必要もあります。非常に短いテストは無意味に小さいと私は主張します。)
Jon Skeet

6
@MarcCliment:どの特定のケースですか?どのCLRですか?どのCPUアーキテクチャ?私のマシンでは、さまざまな結果が得られます。これが、「BTW、productionCollection1.ForEach(...)AddRangeよりもパフォーマンスが高い」などの包括的なステートメントを述べる/受け入れるのが嫌いな理由です。パフォーマンスがそれほど簡単に説明されることはほとんどありません。AddRangeが手軽に打てないこと驚いています-さらに調査する必要があります。
Jon Skeet、2013

15
私は要点(gist.github.com/mcliment/4690433)をBenchmarksDotNetを使用したパフォーマンステストで更新し、適切にテストしました。これAddRangeは、生の速度に最適なオプションです(約4倍で、リストが大きいほど増加します)。示唆する。
Marc Climent 2016

41

指定したカテゴリIDのすべての製品を含むリストが必要であると想定すると、クエリをプロジェクションとして処理し、その後に平坦化操作を行う。それを行うLINQ演算子がありますSelectMany

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

C#4では、SelectManyを次のように短縮できます。 .SelectMany(GetAllProducts)

各IDの製品を表すリストがすでにある場合、必要なのは連結です。、他の人が指摘するように、です。


8
OPが他の理由で個々のリストを必要としない場合、これは優れたソリューションです。
Jon Skeet、2010

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いると述べましたが、彼は私よりはるかに多くの知識を持っているため、これは意味をなさないと述べています。比較したいなら要点があります。


コメントでのジョン・スキートとのあなたの議論に関係なく、私は彼の提案された解決策によって提供されるクリーンさを大いに好みます、これは単にコードの意図に関して不必要な解釈を追加します。
Vix

1
最も明確なオプションは、AddRangeの一般化としてのConcatであり、意味的にはより正確であり、リストをインプレースで変更しないため、チェーン可能になります。ジョンとの話し合いは、清潔さではなくパフォーマンスについてでした。
Marc Climent 2015

私はこのようなものを持ってvar allProducts = lstName.Concat(lstCMSID) .Concat(lstSpecialtyPhys) .ToList();います:それはそれをGridViewに追加しますが、1つの列として。それらを3つの別々の列に分割したいと思います。
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にフラット化し、その後.ToList()メソッドを使用します。


2

リストを1つのリストにマージまたは結合します。

  • 真でなければならないことが1つあります。両方のリストのタイプが等しくなります。

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

この場合、list2は、list1のすべての要素で生成されます。



0

リストの数は少ないが正確な数がわからない場合は、次のようにします。

listsOfProducts オブジェクトで満たされたいくつかのリストが含まれています。

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

listsOfProducts.ForEach(q => q.ForEach(e => productListMerged.Add(e)));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.