mck*_*mey 75 c# linq group-by igrouping ilookup
我一直有麻烦关节之间的差异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>>
Run Code Online (Sandbox Code Playgroud)
这相当于:
var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>
Run Code Online (Sandbox Code Playgroud)
这看起来很像:
var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>
Run Code Online (Sandbox Code Playgroud)
我在以下类比中是否正确?
IGrouping<TKey, TVal>是一个单独的组(即键控序列),类似于KeyValuePair<TKey, TVal>值实际上是一系列元素(而不是单个元素)IEnumerable<IGrouping<TKey, TVal>>是那些序列(类似于迭代时得到的结果)IDictionary<TKey, TVal>ILookup<TKey, TVal>更像是一个IDictionary<TKey, TVal>值实际上是一系列元素的地方Jon*_*eet 75
是的,所有这些都是正确的.
并且ILookup<TKey, TValue>还扩展,IEnumerable<IGrouping<TKey, TValue>>以便您可以迭代所有键/集合对以及(或代替)查找特定键.
我基本上认为ILookup<TKey,TValue>是这样的IDictionary<TKey, IEnumerable<TValue>>.
请记住,这ToLookup是"立即执行"操作(立即执行),而a GroupBy是延迟的.实际上,通过"拉LINQ"工作的方式,当你开始IGrouping从a的结果中拉出s 时GroupBy,它必须无论如何都要读取所有数据(因为你不能在中途切换组),而在其他实现中它可能能够产生流式传输结果.(它在Push LINQ中;我希望LINQ to Events是相同的.)
ILookup和IDictionary之间还有另一个重要的区别:前者强制执行不变性,因为这里没有更改数据的方法(除非消费者执行显式转换).相比之下,IDictionary有像"添加"这样的方法,允许更改数据.因此,从功能编程和/或并行编程的角度来看,ILookup更好.(我只希望有一个版本的ILookup只为一个键而不是一个组分配一个值.)
(顺便说一句,似乎值得指出的是IEnumerable和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; }
}
Run Code Online (Sandbox Code Playgroud)
之后,我们定义了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 }
};
Run Code Online (Sandbox Code Playgroud)
现在我需要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);
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码,我首先进行分组personnels,但迭代它之前,我删除了一些personnels。由于GroupBy使用了延迟执行,所以最终的结果不会包括被移除的项目,因为分组将在foreach这里计算。
输出:
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
Run Code Online (Sandbox Code Playgroud)
但是如果我将上面的代码重写如下:(注意代码与之前的代码相同,只是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);
}
Run Code Online (Sandbox Code Playgroud)
由于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
Run Code Online (Sandbox Code Playgroud)
注:GroupBy和ToLookUp都返回不同类型的了。
您可能会使用 ToDictionary 而不是 ToLookUp,但您需要注意这一点:(参考)
ToLookup() 的用法与 ToDictionary() 非常相似,都允许您指定键选择器、值选择器和比较器。主要区别在于 ToLookup() 允许(并期望)重复键,而 ToDictionary() 不允许
| 归档时间: |
|
| 查看次数: |
9990 次 |
| 最近记录: |