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()
则不允许。