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