join unknown number of lists in linq

前端 未结 3 1126
青春惊慌失措
青春惊慌失措 2021-01-20 02:27

I have a situation where I have generated a number of lists which contain integer values. However, the number of these lists is only known at runtime, and i

相关标签:
3条回答
  • 2021-01-20 02:46
    // lists is a sequence of all lists from l1 to ln
    if (!lists.Any())
       return new List<int>();
    
    IEnumerable<int> r = lists.First();   
    
    foreach(List<int> list in lists.Skip(1))    
       r = r.Intersect(list);
    
    return r.ToList();
    
    0 讨论(0)
  • 2021-01-20 02:51

    I assume that you have a List<List<int>> that holds a variable number of List<int>.

    You can intersect the first list with the second list

    var intersection = listOfLists[0].Intersect(listOfLists[1]);
    

    and then intersect the result with the third list

    intersection = intersection.Intersect(listOfLists[2]);
    

    and so on until intersection holds the intersection of all lists.

    intersection = intersection.Intersect(listOfLists[listOfLists.Count - 1]);
    

    Using a for loop:

    IEnumerable<int> intersection = listOfLists[0];
    
    for (int i = 1; i < listOfLists.Count; i++)
    {
        intersection = intersection.Intersect(listOfLists[i]);
    }
    

    Using a foreach loop (as shown by @lazyberezovsky):

    IEnumerable<int> intersection = listOfLists.First();
    
    foreach (List<int> list in listOfLists.Skip(1))
    {
        intersection = intersection.Intersect(list);
    }
    

    Using Enumerable.Aggregate:

    var intersection = listOfLists.Aggregate(Enumerable.Intersect);
    

    If order is not important, then you can also use a HashSet<T> that you fill with the first list and intersect with with the remaining lists (as shown by @Servy).

    var intersection = new HashSet<int>(listOfLists.First());
    
    foreach (List<int> list in listOfLists.Skip(1))
    {
        intersection.IntersectWith(list);
    }
    
    0 讨论(0)
  • 2021-01-20 02:51

    Here is a simple method to get the intersection of a collection of collections:

    public static IEnumerable<T> Intersect<T>(IEnumerable<IEnumerable<T>> sequences)
    {
        using (var iterator = sequences.GetEnumerator())
        {
            if (!iterator.MoveNext())
                return Enumerable.Empty<T>();
    
            HashSet<T> intersection = new HashSet<T>(iterator.Current);
    
            while (iterator.MoveNext())
                intersection.IntersectWith(iterator.Current);
    
            return intersection;
        }
    }
    

    The idea here is to put all of the items into a set, then intersect that set with each sequence in turn. We can do this with a lot less code using plain LINQ, but this will be populating a new HashSet from the results for each intersection, rather than reusing a single one, so it will have a lot higher overhead despite looking really elegant.

    Here is the less performant but more elegant solution:

    public static IEnumerable<T> Intersect<T>(IEnumerable<IEnumerable<T>> sequences)
    {
        return sequences.Aggregate(Enumerable.Intersect);
    }
    
    0 讨论(0)
提交回复
热议问题