【问题标题】:join unknown number of lists in linq在 linq 中加入未知数量的列表
【发布时间】:2013-02-05 18:01:31
【问题描述】:

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

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 中完成?这是您试图避免从数据库中拉回记录还是在本地系统的内存中处理结果?
  • 类似问题请见:stackoverflow.com/questions/3191810/…
  • Ken,你从哪里得到这些列表的?
  • 每个列表都由从 UDF 或另一个系统返回的主键序列组成。这就是它没有在数据库上完成的原因。运行的查询数量是可变的,因此只有在找到所有结果后才能知道列表的数量

标签: c# linq


【解决方案1】:

我假设您有一个List&lt;List&lt;int&gt;&gt;,其中包含可变编号List&lt;int&gt;

你可以intersect第一个列表和第二个列表

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

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

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

以此类推,直到intersection 持有所有列表的交集。

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 循环(如@lazyberezovsky 所示):

IEnumerable<int> intersection = listOfLists.First();

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

使用Enumerable.Aggregate

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

如果顺序不重要,那么您也可以使用HashSet<T> 填写第一个列表,intersect with 填写其余列表(如 @Servy 所示)。 p>

var intersection = new HashSet<int>(listOfLists.First());

foreach (List<int> list in listOfLists.Skip(1))
{
    intersection.IntersectWith(list);
}

【讨论】:

  • 虽然一切都是正确的,但这并不能回答(不清楚)“但是这些列表的数量仅在运行时才知道”部分问题
  • 将相交变量保持在循环之外应该相当容易,然后您可以(大概)遍历列表 - 编辑:根据lazyberezovsky的回答
  • 我喜欢Aggregate 版本。
  • 感谢您提供的信息,早上第一件事就是尝试一下
【解决方案2】:
// 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();

【讨论】:

  • 这没有回答(不清楚)“但是这些列表的数量仅在运行时才知道”部分问题
  • @ken2k 这是因为不清楚这些列表是如何检索的。我相信 OP 可以枚举它们,但我会在问题中添加评论
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-04
    • 2018-09-26
    • 1970-01-01
    • 2020-02-05
    • 2013-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多