使用Linq通过唯一键创建列表

本文关键字:一键 创建 列表 唯一 Linq 使用 | 更新日期: 2023-09-27 18:24:45

我有一个类型为Dependency:的类

class Dependency
{
    public int Source;
    public int Target:
}

给定一个List<Dependency>列表,我会有以下列表(每一行都是源/目标对):

1, 2
1, 5
2, 1
3, 4
3, 6

是否可以将它们与Linq合并,从而生成以下List<Tuple<int,List<int>>:

1, [2,5]
2, [1]
3, [4,6]

如果有一个几千项的大列表,那么使用Linq是执行上述合并的最快方法吗?

使用Linq通过唯一键创建列表

您可以按如下运算符使用LINQ组:

var items = new List<Dependency>();
// add your items to list
var result = (from i in items
             group i by i.Source
             into gr
             select new Tuple<int, List<int>>(gr.Key, gr.Select(a => a.Target).ToList())).ToList();

上面的查询应该很快,尽管很难与其他实现相同功能的方法进行比较。我建议在实践中测试这一点——编写替代实现并比较性能。

注意:另一个答案推荐C#的group into语法。我的回答显示了类似的东西,即.ToLookup(…)运算符。如果你在问这两者之间的区别,请参见以下问题:ILookup<TKey、TVal>与IGrouping<TKey,TVal>

下面的解决方案不会产生List<Tuple<int, List<int>>>,我不能说它是否是最快的解决方案,但它可能是最简洁的:

ILookup<int,int> multiMap = dependencies.ToLookup(d => d.Source, d => d.Target);

.ToLookup(…)操作符根据Source属性(如第一个lambda指定的)对dependencies进行分组,并且它不会将完整的Dependency对象放入输出中,而是只选择它们的Target值(如第二个可选lambda指定)。

您得到的是ILookup<TKey,TElement>,它本质上类似于Dictionary<TKey,TValue>,只是每个键可以有几个元素(值)。

下面是一个如何在这样的数据结构(所谓的多映射)中迭代所有值的示例:

foreach (IGrouping<int,int> grouping in multiMap)  // enumerate over all groups
foreach (int target in grouping)  // enumerate over all values in one specific group
{
    int source = grouping.Key;  // get the key value of the group
    …
}