简体   繁体   English

ILookup <TKey,TVal>与IGrouping <TKey,TVal>

[英]ILookup<TKey, TVal> vs. IGrouping<TKey, TVal>

I've been having trouble articulating the differences between ILookup<TKey, TVal> and IGrouping<TKey, TVal> , and am curious if I understand it correctly now. 我一直无法阐明ILookup<TKey, TVal>IGrouping<TKey, TVal>之间的差异,如果我现在正确理解它,我很好奇。 LINQ compounded the issue by producing sequences of IGrouping items while also giving me a ToLookup extension method. LINQ通过生成IGrouping项目序列来复杂化问题,同时也为我提供了ToLookup扩展方法。 So it felt like they were the same until I looked more closely. 所以在我仔细观察之前感觉它们是一样的。

var q1 = 
    from n in N
    group n by n.MyKey into g
    select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>

Which is equivalent to: 这相当于:

var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>

Which looks a lot like: 这看起来很像:

var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>

Am I correct in the following analogies? 我在以下类比中是否正确?

  1. An IGrouping<TKey, TVal> is a single group (ie a keyed sequence), analogous to KeyValuePair<TKey, TVal> where the value is actually a sequence of elements (rather than a single element) IGrouping<TKey, TVal>是单个组(即键控序列),类似于KeyValuePair<TKey, TVal> ,其中值实际上是元素序列(而不是单个元素)
  2. An IEnumerable<IGrouping<TKey, TVal>> is a sequence of those (similar to what you get when iterating over an IDictionary<TKey, TVal> IEnumerable<IGrouping<TKey, TVal>>是这些序列(类似于迭代IDictionary<TKey, TVal>时获得的序列)
  3. An ILookup<TKey, TVal> is more like a IDictionary<TKey, TVal> where the value is actually a sequence of elements ILookup<TKey, TVal>更像是IDictionary<TKey, TVal> ,其中值实际上是一系列元素

Yes, all of those are correct. 是的,所有这些都是正确的。

And ILookup<TKey, TValue> also extends IEnumerable<IGrouping<TKey, TValue>> so you can iterate over all the key/collection pairs as well as (or instead of) just looking up particular keys. 并且ILookup<TKey, TValue>还扩展了IEnumerable<IGrouping<TKey, TValue>>因此您可以迭代所有键/​​集合对以及(或代替)查找特定键。

I basically think of ILookup<TKey,TValue> as being like IDictionary<TKey, IEnumerable<TValue>> . 我基本上认为ILookup<TKey,TValue>就像IDictionary<TKey, IEnumerable<TValue>>

Bear in mind that ToLookup is a "do it now" operation (immediate execution) whereas a GroupBy is deferred. 请记住, ToLookup是“立即执行”操作(立即执行),而GroupBy是延迟的。 As it happens, with the way that "pull LINQ" works, when you start pulling IGrouping s from the result of a GroupBy , it has to read all the data anyway (because you can't switch group midway through) whereas in other implementations it may be able to produce a streaming result. 实际上,随着“拉LINQ”工作的方式,当你开始从GroupBy的结果中拉出IGrouping时,它必须无论如何都要读取所有数据(因为你不能在中途切换组)而在其他实现中它可能能够产生流式传输结果。 (It does in Push LINQ; I would expect LINQ to Events to be the same.) (它在Push LINQ中;我希望LINQ to Events是相同的。)

There is another important difference between ILookup and IDictionary: the former enforces immutability in the sense that here are no methods for changing the data (except when the consumer performs an explicit cast). ILookup和IDictionary之间还有另一个重要的区别:前者强制执行不变性,因为这里没有更改数据的方法(除非消费者执行显式转换)。 By contrast, IDictionary has methods like "Add" which allow changing the data. 相比之下,IDictionary有像“添加”这样的方法,允许更改数据。 So, from the perspective of functional-programming and/or parallel programming, ILookup is nicer. 因此,从功能编程和/或并行编程的角度来看,ILookup更好。 (I only wish there was also a version of ILookup that assigns only one value to a key rather than a group.) (我只希望有一个版本的ILookup只为一个键而不是一个组分配一个值。)

(Btw., it seems worth pointing out that the relationship between IEnumerable and IList is somewhat similar to the one between ILookup and IDictionary - the former is immutable, the latter is not.) (顺便说一句,似乎值得指出的是IEnumerable和IList之间的关系有点类似于ILookup和IDictionary之间的关系 - 前者是不可变的,后者不是。)

GroupBy and ToLookUp has almost same functionality EXCEPT this: Reference GroupByToLookUp具有几乎相同的功能, 除了这个: 参考

GroupBy: The GroupBy operator returns groups of elements based on some key value. GroupBy:GroupBy运算符根据某个键值返回元素组。 Each group is represented by IGrouping object. 每个组由IGrouping对象表示。

ToLookup: ToLookup is the same as GroupBy; ToLookup:ToLookup与GroupBy相同; the only difference is the execution of GroupBy is deferred whereas ToLookup execution is immediate. 唯一的区别是GroupBy的执行被延迟,而ToLookup立即执行。

Lets clear the difference using sample code. 让我们使用示例代码清除差异。 suppose that we have a class representing Person model: 假设我们有一个表示Person模型的类:

class Personnel
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public int Level { get; set; }
}

after that we define a list of personnels as below: 之后我们定义一个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 }
    };

Now I need to get the personnels grouped by their level. 现在我需要按照他们的级别对personnels分组。 I have two approach here. 我有两种方法。 using GroupBy or ToLookUp . 使用GroupByToLookUp If I use GroupBy , as stated before, it will use deferred execution, this means, that when you iterate through the collection the next item may or may not be computed until it is called for. 如果我使用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);
    }

In the above code, I firstly grouped the personnels , but before iterating it, I removed some personnels . 在上面的代码中,我首先对personnels分组,但在迭代之前,我删除了一些personnels As GroupBy uses deferred execution, so the final result will not include the removed items, because grouping will be computing in the foreach point here. 由于GroupBy使用延迟执行,因此最终结果将不包括已删除的项目,因为分组将在此处的foreach点进行计算。

Output: 输出:

2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

But if I rewrite the above code as below:(note that code is same as the previous code except GroupBy is replaced by ToLookUp ) 但是,如果我重写上面的代码如下:(注意代码与前面的代码相同,除了GroupByToLookUp取代)

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

As ToLookUp uses immediate execution, it means that when I call the ToLookUp method, result is generated and group is applied, so if I remove any item from personnels prior to iteration, that wont effect the final result. 由于ToLookUp使用立即执行,这意味着当我调用ToLookUp方法时,生成结果并应用组,因此如果我在迭代之前从personnels删除任何项目,则不会影响最终结果。

Output: 输出:

1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

Note: GroupBy and ToLookUp both return different types too. 注意: GroupByToLookUp也返回不同的类型。

You might use ToDictionary instead of ToLookUp, but you need to pay attention to this:( reference ) 您可能使用ToDictionary而不是ToLookUp,但您需要注意这一点:( 参考

The usage of ToLookup() is very similar to that of ToDictionary(), both allow you to specify key selectors, value selectors, and comparers. ToLookup()的用法与ToDictionary()的用法非常相似,都允许您指定键选择器,值选择器和比较器。 The main difference is that ToLookup() allows (and expects) the duplicate keys whereas ToDictionary() does not 主要区别在于ToLookup()允许(并期望)重复键,而ToDictionary()则不允许

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 分组 <TKey,TElement> 合计 - IGrouping<TKey,TElement> Totals 推荐的转换IGrouping的方法 <TKey, TValue> 到IDictionary <TKey, IEnumerable<TValue> &gt; - Recommended way to convert IGrouping<TKey, TValue> to IDictionary<TKey, IEnumerable<TValue>> 不使用 IGrouping 的 ListView 分组<tkey, tmodel></tkey,> - ListView Grouping without using IGrouping<TKey, TModel> 如何转换查找的元素;即ILookup <TKey,Derived>到ILookup <TKey,Base>? - How to cast TElement of lookup; i.e. ILookup<TKey, Derived> to ILookup<TKey, Base>? ConcurrentDictionary <TKey,TValue> vs词典 <TKey,TValue> - ConcurrentDictionary<TKey,TValue> vs Dictionary<TKey,TValue> 为什么不能/不能IDictionary <TKey,TValue>实现ILookup <TKey,TValue>? - Why doesn't/couldn't IDictionary<TKey,TValue> implement ILookup<TKey,TValue>? 不应该ILookup <TKey, TElement> 是(声明)TElement中的协变? - Shouldn't ILookup<TKey, TElement> be (declared) covariant in TElement? 是否可以在 IEnumerable 中返回将 TElement 与 TKey 匹配的匿名类型<IGrouping<TKey, TElement> &gt; GroupBy() 返回? - Is it possible to return an anonymous type that matches TElement to TKey in IEnumerable<IGrouping<TKey, TElement>> returned by GroupBy()? 如何为IGrouping设置默认值 <TKey, TSource> 计数= 0? - How to Make a default value for IGrouping<TKey, TSource> with count = 0? MVC 强类型 IQueryable <igrouping<tkey, telement> > model </igrouping<tkey,> - MVC Strongly typed IQueryable<IGrouping<TKey, TElement>> model
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM