LINQ中的Group by:通过实际示例理解分组
\n\n如果你曾经用C#编写过针对集合的查询,那么你很可能遇到过这样的问题:“我该如何对数据进行分组?” LINQ中的group by 是Stack Overflow上最热门的话题之一(拥有数万次浏览)。这并非偶然:分组乍看起来很简单,但实际上,初学者常常会踩到一些典型的“坑”,比如如何选择组中的第一条记录、如何计算总和或进行嵌套分组。
\n\n在本文中,我们将探讨关于 LINQ GroupBy 的5个最常见问题,并提供可行的解决方案。我们开始吧!
\n\n1. LINQ中的GroupBy是如何工作的?基本语法
\n\nGroupBy 方法类似于SQL中的GROUP BY语句。它根据指定的键将序列拆分为多个组。结果是一个 IGrouping<TKey, TElement> 对象的集合,其中每个对象包含一个键以及属于该组的所有元素。
这是一个最简单的例子。假设我们有一个学生列表:
\n\npublic class Student\n{\n public string Name { get; set; }\n public string Group { get; set; }\n public int Score { get; set; }\n}\n\nvar students = new List<Student>\n{\n new Student { Name = "安娜", Group = "A", Score = 85 },\n new Student { Name = "鲍里斯", Group = "B", Score = 90 },\n new Student { Name = "维卡", Group = "A", Score = 78 },\n new Student { Name = "格列布", Group = "B", Score = 92 }\n};\n\n按组名进行分组:
\n\nvar grouped = students.GroupBy(s => s.Group);\n\nforeach (var group in grouped)\n{\n Console.WriteLine($"组: {group.Key}");\n foreach (var student in group)\n {\n Console.WriteLine($" {student.Name} — {student.Score}");\n }\n}\n\n输出:
\n组: A\n 安娜 — 85\n 维卡 — 78\n组: B\n 鲍里斯 — 90\n 格列布 — 92\n\n一切都很简单。但正如常言道,魔鬼在于细节。
\n\n2. 如何从每个组中选择第一条记录?
\n\n这是关于 LINQ中的group by 最常见的问题。假设我们需要从每个组中获取一名最佳学生(分数最高)。该怎么做?
\n\n解决方案是将 GroupBy 与 First() 或 OrderByDescending 结合使用:
var bestStudents = students\n .GroupBy(s => s.Group)\n .Select(g => g.OrderByDescending(s => s.Score).First());\n\nforeach (var student in bestStudents)\n{\n Console.WriteLine($"{student.Name} — {student.Group} — {student.Score}");\n}\n\n结果:安娜(85)和格列布(92)。请注意:在 Select 内部,我们对组进行排序并取第一个元素。这就是“如何实现LINQ group by first”的答案。
重要提示: 如果组为空,First() 会抛出异常。如果可能发生这种情况,请使用 FirstOrDefault()。
3. 如何计算每个组的总和、计数或平均值?
\n\n分组后,通常不仅需要遍历元素,还需要获取聚合值。例如,每个组的总分或平均分。
\n\n使用 Sum、Count、Average:
var groupStats = students\n .GroupBy(s => s.Group)\n .Select(g => new\n {\n Group = g.Key,\n Count = g.Count(),\n TotalScore = g.Sum(s => s.Score),\n AverageScore = g.Average(s => s.Score)\n });\n\nforeach (var stat in groupStats)\n{\n Console.WriteLine($"组 {stat.Group}: {stat.Count} 名学生, 总分 {stat.TotalScore}, 平均分 {stat.AverageScore:F2}");\n}\n\n输出:
\n组 A: 2 名学生, 总分 163, 平均分 81.50\n组 B: 2 名学生, 总分 182, 平均分 91.00\n\n也可以使用 Min 和 Max —— 在