ILookup <TKey,TVal>与IGrouping <TKey,TVal>
我一直在阐明ILookup<TKey, TVal>
和IGrouping<TKey, TVal>
之间的差异,而且我很好奇,如果我现在正确地理解它的话。 LINQ通过生成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
则被延迟。 碰巧,“拉LINQ”的方式工作,当你从一个GroupBy
的结果开始拉IGrouping
,它必须读取所有的数据(因为你不能中途切换组),而在其他实现它可能能够产生stream式传输结果。 (它在推LINQ;我希望LINQ事件是相同的。)
ILookup和IDictionary之间还有一个重要的区别:前者强调不变性,因为在这里没有改变数据的方法(除了消费者执行显式的转换)。 相比之下,IDictionary有像“添加”,允许改变数据的方法。 因此,从function编程和/或并行编程的angular度来看,ILookup更好。 (我只希望还有一个ILookup版本,它只为一个密钥而不是一个组分配一个值。)
(顺便说一句,似乎值得指出IEnumerable和IList之间的关系有点类似于ILookup和IDictionary之间的关系 – 前者是不可变的,后者不是。)