2017-07-22 11 views
0

検索しましたが、2つのリストに関連する回答のみが見つかりました。しかし、2人以上のときはどうですか?C#の複数のリストで共通項目を見つけるlinq

List 1 = 1,2,3,4,5 
List 2 = 6,7,8,9,1 
List 3 = 3,6,9,2,0,1 
List 4 = 1,2,9,0,5 
List 5 = 1,7,8,6,5,4 
List 6 = 1 
List 7 = 

共通項目の取得方法は?あなたが見ることができるようにそれらの1つが空であるので、共通は空ですが、私は空のリストをスキップする必要があります。

+1

あなたはあなたドンのように空のリストをスキップする必要がある場合は、新しいリストに、前の 'Intersect'などの結果 –

+1

に' Intersect'を適用し、その後、2つのリストのための 'Intersect'を使用することができます」結果が空になるようにしたい場合は、 'Lists.Where(l => l.Any())'だけでフィルタリングすることができます。 – juharr

+0

私は自分の答えを更新しました。空リストとnullをスキップできます。 – Han

答えて

2
var data = new [] { 
    new List<int> {1, 2, 3, 4, 5}, 
    new List<int> {6, 7, 8, 9, 1}, 
    new List<int> {3, 6, 9, 2, 0, 1}, 
    new List<int> {1, 2, 9, 0, 5}, 
    new List<int> {1, 7, 8, 6, 5, 4}, 
    new List<int> {1}, 
    new List<int> {}, 
    null 
}; 

IEnumerable<int> temp = null; 
foreach (var arr in data) 
    if (arr != null && arr.Count != 0) 
     temp = temp == null ? arr : arr.Intersect(temp); 
4

あなたはチェーンIntersectことができます。

List<int> List1 = new List<int> {1, 2, 3, 4, 5}; 
List<int> List2 = new List<int> { 6, 7, 8, 9, 1 }; 
List<int> List3 = new List<int> { 3, 6, 9, 2, 0, 1 }; 
List<int> List4 = new List<int> { 1, 2, 9, 0, 5 }; 
List<int> List5 = new List<int> { 1, 7, 8, 6, 5, 4 }; 
List<int> List6 = new List<int> { 1 }; 

List<int> common = List1 
    .Intersect(List2) 
    .Intersect(List3) 
    .Intersect(List4) 
    .Intersect(List5) 
    .Intersect(List6) 
    .ToList(); 
+0

アイテムのないリストをスキップする方法は? – Nofuzy

+0

@Paparazziが私の質問を更新しました。 – Nofuzy

2
var data = new List<List<int>> { 
    new List<int> {1, 2, 3, 4, 5}, 
    new List<int> {6, 7, 2, 8, 9, 1}, 
    new List<int> {3, 6, 9, 2, 0, 1}, 
    new List<int> {1, 2, 9, 0, 5}, 
    new List<int> {1, 7, 8, 6, 2, 5, 4}, 
    new List<int> {1, 7, 2} 
}; 


List<int> res = data 
    .Aggregate<IEnumerable<int>>((a, b) => a.Intersect(b)) 
    .ToList(); 

集計の種類が明示的に指定され、それ以外の場合は二つのリストの凝集があまりにもリストでなければならないであろう。簡単に並列で実行するように適合させることができます。

EDITそれは並列に実行されません...除き

。問題はIEnumerableの操作が遅延されるため、論理的に並列コンテキストでマージされても、実際のマージは単一スレッドのToList()で発生します。並列実行のためには、IEnumerableを残して、リストに戻る方が良いでしょう:

List<int> res = data 
    .AsParallel() 
    .Aggregate((a, b) => a.Intersect(b).ToList()); 
2

一つの方法は、HashSetを使用することです。最初のコレクションのアイテムをハッシュに配置し、最初のコレクションの後に各コレクションを反復し、新しいコレクションを作成して、現在のコレクションからハッシュ内にあるアイテムに追加することができます。最後に、共通のハッシュセットを全体のハッシュセットに割り当て、すべてが空の場合は中断します。最後に、全体のハッシュセットを返します。

public IEnumerable<T> CommonItems<T>(IEnumerable<IEnumerable<T>> collections) 
{ 
    if(collections == null) 
     throw new ArgumentNullException(nameof(collections)); 

    using(var enumerator = collections.GetEnumerator()) 
    { 
     if(!enumerator.MoveNext()) 
      return Enumerable<T>.Empty(); 

     var overall = new HashSet<T>(enumerator.Current); 
     while(enumerator.MoveNext()) 
     { 
      var common = new HashSet<T>(); 
      foreach(var item in enumerator.Current) 
      { 
       if(hash.Contains(item)) 
        common.Add(item); 
      } 

      overall = common; 
      if(overall.Count == 0) 
       break; 
     } 

     return overall; 
    } 
} 
+0

IEnumerableを2回列挙するのは悪い習慣です。毎回同じシーケンスが得られる保証はありませんが、アルゴリズムはそれに依存しています(Skip(1)で)。シーケンスを2回列挙することは保証されていません。最後に、複数の列挙は非常に高価な場合もあります。 –

+0

@AntonínLejsekTrueのため、代わりに列挙子を使用するバージョンがあります。 – juharr

関連する問題