ILookup<TKey, TVal=""> 与IGrouping<TKey, TVal="">
题
我已经有麻烦阐明之间的差异 ILookup<TKey, TVal>
和 IGrouping<TKey, TVal>
, 我很好奇如果我的理解是正确的。皇宫加剧了这一问题通过生产序列 IGrouping
项目的同时,也给了我一个 ToLookup
扩展的方法。所以感觉就像他们一样直到我看起来更密切的合作。
var q1 =
from n in N
group n by n.MyKey into g
select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>
这相当于:
var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>
这看起来很像:
var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>
我正在下面的比喻?
- 一个
IGrouping<TKey, TVal>
是一个单一的组(即键顺序),类似于KeyValuePair<TKey, TVal>
其中值是实际上的序列元素(而不是单个元素) - 一个
IEnumerable<IGrouping<TKey, TVal>>
是一个顺序(相似你会得到什么,当一个迭代IDictionary<TKey, TVal>
- 一个
ILookup<TKey, TVal>
更像是IDictionary<TKey, TVal>
其中值实际上是一种序列的元素
解决方案
是的,所有这些都是正确的。
和 ILookup<TKey, TValue>
还延伸 IEnumerable<IGrouping<TKey, TValue>>
所以你可以迭代过的所有关键/收集对以及(或不是)只是寻找特定的钥匙。
我基本上认为的 ILookup<TKey,TValue>
作为喜欢 IDictionary<TKey, IEnumerable<TValue>>
.
铭记 ToLookup
是"现在就这样做"操作(即时执行),而一个 GroupBy
被推迟。如发生这种情况,与的方式,以"拉皇宫"运作,当你开始拉 IGrouping
s的结果 GroupBy
, 它具有读所有数据(因为你不能开关组中通过)而在其他的实现方式也可能能够产生一流的结果。(它在推皇宫;我希望皇宫的事件是相同的。)
其他提示
还有另外一个重要的差异之间的ILookup和IDictionary:前者强制执行不可变性的意义上说,这是无法改变的数据(除非消费者执行一个明确的铸).相比之下,IDictionary有方法,如"增加",允许改变的数据。因此,从这个角度的功能编程和/或平行编程,ILookup是更好。(我只希望还有一个版本的ILookup分配的唯一价值的一个关键,而不是一个组。)
(顺便说一句., 它似乎值得指出的是,之间的关系类型和IList是有点类似于一个之间的ILookup和IDictionary-前是不可改变的,后者不是。)
GroupBy
和 ToLookUp
有几乎相同的功能 除了 这样的: 参考
GroupBy:该GroupBy操作者返回群体的基于一些元素 关键的价值。每一组表示由IGrouping 对象。
ToLookup:ToLookup相同GroupBy;唯一的区别 是执行GroupBy是推迟而ToLookup执行 即时的。
允许明显的差异使用的样本的代码。假设我们有一类代表 Person
模型:
class Personnel
{
public int Id { get; set; }
public string FullName { get; set; }
public int Level { get; set; }
}
之后,我们定义的一个列表中的 personnels
如下:
var personnels = new List<Personnel>
{
new Personnel { Id = 1, FullName = "P1", Level = 1 },
new Personnel { Id = 2, FullName = "P2", Level = 2 },
new Personnel { Id = 3, FullName = "P3", Level = 1 },
new Personnel { Id = 4, FullName = "P4", Level = 1 },
new Personnel { Id = 5, FullName = "P5", Level =2 },
new Personnel { Id = 6, FullName = "P6", Level = 2 },
new Personnel { Id = 7, FullName = "P7", Level = 2 }
};
现在我需要得到的 personnels
分组通过他们的水平。我有两个方法在这里。使用 GroupBy
或 ToLookUp
.如果我用 GroupBy
, 如以前所说的,它将使用延迟执行,这意味着,当你迭代过收集下一个项目可以或不可以被计算的,直到它被称为。
var groups = personnels.GroupBy(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
在上述码,我首先分组 personnels
, 但之前迭代它,我删除一些 personnels
.作为 GroupBy
使用延迟执行,因此最终结果将不包括删除的项目,因为分组将在计算中 foreach
点在这里。
输出:
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
但是,如果我重写上述代码如下:(注意,代码是一样的前除了代码 GroupBy
替换 ToLookUp
)
var groups = personnels.ToLookup(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
作为 ToLookUp
使用即时执行,这意味着,当我打电话的 ToLookUp
方法,结果是产生和小组应用,所以如果我删除任何项目 personnels
前次迭代,这不会影响最终结果。
输出:
1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
注: GroupBy
和 ToLookUp
两者的回归不同的类型。
你可能会使用ToDictionary而不是ToLookUp,但是你需要注意这一点:(参考)
使用的ToLookup()非常相似的ToDictionary(), 两者都允许你到指定的关键选择、价值选择,以及 比较器.主要差别是,ToLookup()允许(和 预期)的重复键而ToDictionary()不