Find common items in multiple lists in C# linq

北战南征 提交于 2020-12-13 05:41:01

问题


I searched, but I found only answers which related to two lists. But what about when they are more than two?

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 =

How to get the common items? as you can see one of them is empty, so the common will be empty, but I need to skip empty lists.


回答1:


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



回答2:


You can chain 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();



回答3:


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

The type of Aggregate is explicitly given, otherwise aggregation of two Lists would have to be List too. It can be easily adapted to run in parallel:

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

EDIT

Except... it does not run in parallel. The problem is operations on IEnumerable are deferred, so even if they are logically merged in parallel context, the actual merging occurs in the ToList(), which is single threaded. For parallel execution it would be better to leave IEnumerable and return to the Lists:

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



回答4:


One way is to use a HashSet. You can put the items of the first collection in the hash, then iterate each collection after the first and create an new hash that you add items from the current collection to if it's in the hash. At the end you assign that common hash set to the overall one and break if it's every empty. At the end you just return the overall hash set.

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


来源:https://stackoverflow.com/questions/45255495/find-common-items-in-multiple-lists-in-c-sharp-linq

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!