C#Linq查询(五):聚合与数值计算(纯干货)
本文介绍了LINQ中的聚合与数值计算方法,包括Max/Min/Sum/Average等基础操作,以及.NET 6+新增的MaxBy/MinBy和灵活的Aggregate方法。这些方法可用于快速计算序列中的最大值、最小值、总和、平均值等统计信息,支持数值类型和对象属性。其中,MaxBy/MinBy返回符合条件的元素本身,Aggregate则支持自定义累积逻辑。需要注意的是,不同方法对空序列的处理方式
五、聚合与数值计算
用于合并元素或计算统计值。这类操作能快速从序列中提取关键信息(如最大值、总和、自定义累积结果),是数据分析和统计场景的核心工具。
1. Max() / Min() / Sum() / Average()
返回序列的最大 / 最小 / 和 / 平均值(仅适用于数值类型,或对象中可转为数值的属性)。
性能特性:需遍历整个序列(O (n) 复杂度),对空序列的处理因方法而异(如 Sum 返回 0,Max 抛异常)。
典型场景:数值统计(如成绩总分、平均工资、最大订单金额)。
示例 1:基础数值序列
var scores = new List<int> { 80, 90, 75, 85, 95 };
// 最大值
int max = scores.Max(); // 95
// 最小值
int min = scores.Min(); // 75
// 总和
int total = scores.Sum(); // 425
// 平均值(返回 double)
double avg = scores.Average(); // 85.0
示例 2:对象集合的数值属性统计
public class Order {
public int Id { get; set; }
public decimal Amount { get; set; } // 订单金额(数值类型)
public DateTime CreateTime { get; set; }
}
var orders = new List<Order> {
new Order { Id = 1, Amount = 199.9m },
new Order { Id = 2, Amount = 299.5m },
new Order { Id = 3, Amount = 99.9m }
};
// 最大订单金额
decimal maxAmount = orders.Max(o => o.Amount); // 299.5m
// 订单总金额
decimal totalAmount = orders.Sum(o => o.Amount); // 599.3m
// 平均订单金额
double avgAmount = orders.Average(o => o.Amount); // ~199.77
注意:空序列处理
var emptyList = new List<int>();
// Sum() 对空序列返回 0(安全)
int sum = emptyList.Sum(); // 0
// Max()/Min()/Average() 对空序列抛 InvalidOperationException(需提前判断)
if (emptyList.Any()) {
int max = emptyList.Max();
} else {
// 处理空序列逻辑(如返回默认值)
}
2. MaxBy(keySelector) / MinBy(keySelector)(.NET 6+)
根据键选择器(如对象的某个属性)返回序列中键最大 / 最小的元素(返回元素本身,而非键值)。
性能特性:遍历一次序列(O (n) 复杂度),比先查键再找元素更高效。
典型场景:找 “年龄最大的用户”“价格最低的商品” 等(需返回元素而非单纯的键值)。
示例 1:基础对象集合
public class Person {
public string Name { get; set; }
public int Age { get; set; }
}
var people = new List<Person> {
new Person { Name = "张三", Age = 25 },
new Person { Name = "李四", Age = 30 },
new Person { Name = "王五", Age = 22 }
};
// 按年龄找最大的人(返回 Person 对象)
Person oldest = people.MaxBy(p => p.Age); // 李四(30岁)
// 按年龄找最小的人
Person youngest = people.MinBy(p => p.Age); // 王五(22岁)
示例 2:复杂键选择
public class Product {
public string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; } // 库存
}
var products = new List<Product> {
new Product { Name = "手机", Price = 3999, Stock = 50 },
new Product { Name = "电脑", Price = 5999, Stock = 30 },
new Product { Name = "平板", Price = 2999, Stock = 40 }
};
// 找库存最少的商品
Product leastStock = products.MinBy(p => p.Stock); // 电脑(30库存)
// 找单价最高的商品
Product mostExpensive = products.MaxBy(p => p.Price); // 电脑(5999元)
3. Aggregate
自定义累积操作(从初始值开始,按规则逐步合并元素)。支持灵活的聚合逻辑(如字符串拼接、复杂计算、多值累积)。
核心逻辑:Aggregate(初始值, (累积结果, 当前元素) => 新累积结果)
- 从 “初始值” 开始,逐个处理元素,用 “累积函数” 更新结果,最终返回最终累积值。
性能特性:遍历一次序列(O (n) 复杂度),适合自定义聚合场景。
典型场景:字符串拼接、自定义求和(如带权重的累加)、多字段联合计算等。
示例 1:基础累积(模拟 Sum)
var numbers = new List<int> { 1, 2, 3, 4 };
// 累加所有元素(初始值 0,每次累加当前元素)
int sum = numbers.Aggregate(0, (currentSum, num) => currentSum + num); // 10(0+1+2+3+4)
示例 2:字符串拼接
var words = new List<string> { "Hello", "World", "C#", "LINQ" };
// 拼接成句子(初始值空字符串,每次追加当前单词+空格)
string sentence = words.Aggregate("", (currentStr, word) => currentStr + word + " ");
// 结果:"Hello World C# LINQ "(注意末尾有空格,可后续处理)
// 优化:去掉末尾空格
string trimmed = words.Aggregate("", (s, w) => $"{s}{(s == "" ? "" : " ")}{w}");
// 结果:"Hello World C# LINQ"
示例 3:复杂自定义聚合(多值计算)
public class Student {
public string Name { get; set; }
public int Score { get; set; }
}
var students = new List<Student> {
new Student { Name = "张三", Score = 80 },
new Student { Name = "李四", Score = 90 },
new Student { Name = "王五", Score = 70 }
};
// 用 Aggregate 同时计算总分和平均分(返回匿名对象)
var result = students.Aggregate(
new { Total = 0, Count = 0 }, // 初始值:总分0,数量0
(acc, student) => new {
Total = acc.Total + student.Score, // 累加分数
Count = acc.Count + 1 // 计数+1
},
acc => new { // 最终转换:计算平均分
Total = acc.Total,
Avg = (double)acc.Total / acc.Count
}
);
Console.WriteLine($"总分:{result.Total},平均分:{result.Avg}"); // 总分:240,平均分:80
核心对比与注意事项
| 方法 | 核心逻辑 | 返回类型 | 适用场景 |
|---|---|---|---|
Max() |
求序列最大值 | 数值(如 int、decimal) | 基础数值 / 属性最大值统计 |
Min() |
求序列最小值 | 数值 | 基础数值 / 属性最小值统计 |
Sum() |
求序列总和 | 数值 | 求和(空序列返回 0) |
Average() |
求序列平均值 | double | 平均计算(空序列抛异常) |
MaxBy(key) |
按键找最大元素 | 序列元素本身 | 需返回 “元素” 而非键值时 |
MinBy(key) |
按键找最小元素 | 序列元素本身 | 需返回 “元素” 而非键值时 |
Aggregate |
自定义累积操作 | 自定义类型(由初始值决定) | 复杂聚合(如拼接、多值计算) |
关键注意事项
- 空序列处理:
Sum()对空序列返回 0;Max()/Min()/Average()对空序列抛InvalidOperationException(建议先通过Any()判断非空)。MaxBy()/MinBy()对空序列抛异常;Aggregate若为空序列,直接返回初始值。
- 非数值类型兼容:
Max()/Min()支持实现IComparable的非数值类型(如string按字典序比较)。
示例:new List<string> { "b", "a", "c" }.Max()→ “c”(字典序最大)。
- 性能优化:
- 简单统计优先用
Max/Sum等内置方法(底层优化更高效);复杂逻辑再用Aggregate。 MaxBy/MinBy比 “先查键再找元素” 更高效(仅遍历一次)。
- 简单统计优先用
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)