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> 

我在下面的类比中是否正确?

  1. IGrouping<TKey, TVal>是一个单独的组(即一个键控序列),类似于KeyValuePair<TKey, TVal> ,其中的值实际上是一个元素序列(而不是单个元素)
  2. 一个IEnumerable<IGrouping<TKey, TVal>>是这些序列(类似于迭代IDictionary<TKey, TVal>
  3. 一个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之间的关系 – 前者是不可变的,后者不是。)