加入linq中未知数量的列表

本文关键字:列表 未知数 linq 加入 | 更新日期: 2023-09-27 18:00:14

我有一种情况,我生成了许多包含整数值的列表。但是,这些列表的数量仅在运行时才知道,并且结果列表中存在的整数必须存在于所有列表中。有没有一种方法可以将所有这些列表合并到一个列表中?

List<int> l1 = {1, 2, 3, 4};
List<int> l2 = {2, 3, 5, 7, 9};
List<int> l3 = {3, 9, 10};
List<int> ln = {....};

结果列表应如下所示

List<int> r = {3};

用linq或任何其他方法可以做到这一点吗?

加入linq中未知数量的列表

我假设您有一个List<List<int>>,它包含一个变量数List<int>

您可以将第一个列表与第二个列表相交

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

然后将结果与第三列表相交

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

依此类推,直到CCD_ 3保持所有列表的交集。

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

使用for循环:

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

使用foreach循环(如@lazybrezovsky所示):

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

使用可枚举。聚合:

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

如果顺序不重要,那么您也可以使用HashSet<T>填充第一个列表并与其余列表相交(如@Servy所示)。

var intersection = new HashSet<int>(listOfLists.First());
foreach (List<int> list in listOfLists.Skip(1))
{
    intersection.IntersectWith(list);
}
// 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();

这里有一个简单的方法来获取集合的交集:

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

这里的想法是将所有项目放入一个集合中,然后依次将该集合与每个序列相交。使用普通LINQ,我们可以用更少的代码来实现这一点,但这将从每个交集的结果中填充一个新的HashSet,而不是重用一个,因此尽管看起来非常优雅,但它的开销会高得多。

以下是性能较差但更优雅的解决方案:

public static IEnumerable<T> Intersect<T>(IEnumerable<IEnumerable<T>> sequences)
{
    return sequences.Aggregate(Enumerable.Intersect);
}