groupby是linq中用于按指定键分组的核心操作符,返回ienumerable,支持单属性、多级、复合键分组及自定义比较器,并可结合select实现聚合计算。

GroupBy 是 LINQ 中最常用也最强大的操作符之一,它能将集合按指定键(key)分组,生成一个“组的集合”,每组内部包含具有相同键的所有元素。它不是简单地去重或排序,而是为后续聚合(如求和、计数、平均值)打下基础。
GroupBy 的基本用法:按单个属性分组
最常见场景是按对象的某个属性(如 Category、Status、Year)分组。返回类型是 IEnumerable<igrouping tsource>></igrouping>,其中每个 IGrouping 既是一个分组,本身也继承自 IEnumerable<tsource></tsource>,可直接遍历其元素。
示例:按产品类别分组
var products = new List<Product> {
new Product { Name = "苹果", Category = "水果", Price = 5.0 },
new Product { Name = "香蕉", Category = "水果", Price = 3.5 },
new Product { Name = "牛奶", Category = "乳制品", Price = 8.0 }
};
<p>var grouped = products.GroupBy(p => p.Category);</p><p>foreach (var group in grouped)
{
Console.WriteLine($"类别:{group.Key}");
foreach (var p in group) // group 本身可枚举
Console.WriteLine($" - {p.Name} ({p.Price:C})");
}</p>带聚合的 GroupBy:Count、Sum、Average 等一步到位
单纯分组后还需手动遍历计算?没必要。可以在 GroupBy 后接投影(Select),对每个分组做聚合操作,直接得到结构化结果。
- 统计每类商品数量:
.Select(g => new { Category = g.Key, Count = g.Count() }) - 计算每类平均价格:
.Select(g => new { Category = g.Key, AvgPrice = g.Average(p => p.Price) }) - 获取每类最高价商品:
.Select(g => g.OrderByDescending(p => p.Price).First())
注意:聚合方法(如 Count()、Average())作用在 g(即 IGrouping)上,它已经是同键元素的集合。
多级分组与复合键:用匿名类型或元组构造 Key
需要按多个字段联合分组(如“年份 + 类别”)时,不能写 GroupBy(x => x.Year, x => x.Category)——那是错误语法。正确做法是让 key 成为一个组合对象:
- 用匿名类型:
.GroupBy(x => new { x.Year, x.Category }) - 用 ValueTuple(推荐,更轻量):
.GroupBy(x => (x.Year, x.Category))
此时 g.Key.Year 和 g.Key.Category 可直接访问;投影时也能自然解构,比如 .Select(g => new { g.Key.Year, g.Key.Category, Total = g.Sum(p => p.Sales) })。
自定义相等比较器:当默认比较不满足需求时
默认情况下,GroupBy 对 key 使用引用/值类型的默认相等逻辑。若需按忽略大小写、四舍五入、或自定义规则分组,可传入 IEqualityComparer<tkey></tkey> 实现。
例如:按价格四舍五入到整数分组
public class RoundedPriceComparer : IEqualityComparer<decimal>
{
public bool Equals(decimal x, decimal y) => Math.Round(x) == Math.Round(y);
public int GetHashCode(decimal obj) => Math.Round(obj).GetHashCode();
}
<p>var groupedByRoundedPrice = products.GroupBy(p => p.Price, new RoundedPriceComparer());</p>注意:自定义比较器必须同时实现 Equals 和 GetHashCode,且逻辑保持一致。
基本上就这些。GroupBy 看似简单,但灵活组合 key 选择、投影和聚合,就能应对绝大多数报表、统计、数据透视类需求。不复杂但容易忽略细节——尤其是 key 的类型稳定性与比较逻辑的一致性。









