今天,咱们将着眼于五个用于序列的聚合运算。不少时候当咱们在对序列进行操做时,咱们想要作基于这些序列执行某种汇总而后,计算结果。html
Enumerable 静态类的LINQ扩展方法能够作到这一点 。就像以前大多数的LINQ扩展方法同样,这些是基于IEnumerable <TSource>序列的操做。app
它有两种形式:函数
在这里请注意几件事情。测试
首先,尽管在C#中支持许多类型,SUM()方法-非投影式-只支持int,long,double,decimal,single 。 3d
1: // 正确
2: double[] data = { 3.14, 2.72, 1.99, 2.32 };
3: var result = data.Sum();
4:
5: //不支持
6: short[] shortData = { 1, 2, 5, 7 };
7:
8: // 出现编辑错误
9: var shortResult = shortData.Sum();code
还要注意的是,你能够操做上面这些类型容许Null 的可空值变种。在以前咱们讨论过,可为空的类型能够是一个棘手的事情,但用SUM()时咱们不用担忧,由于全部的空值在求和时都排除了 :htm
var data = new List<int?> { 1, 3, 9, 13, null, 7, 12, null };
var result = data.Sum();对象
第二,投影形式是一个比较有趣和有用的方法:
为了说明这一点,让咱们假设一个简单的POCO Employee:blog
public sealed class Employee
{
public string Name { get; set; }
public double Salary { get; set; }
public short Dependents { get; set; }
}
接口
var employees = new List<Employee>
{
new Employee { Name = "Bob", Salary = 35000.00, Dependents = 0 },
new Employee { Name = "Sherry", Salary = 75250.00, Dependents = 1 },
new Employee { Name = "Kathy", Salary = 32000.50, Dependents = 0 },
new Employee { Name = "Joe", Salary = 17500.00, Dependents = 2 },
};
而后咱们就可使用投影方式得到Salary 的总值:
var totalSalary = employees.Sum(e => e.Salary);
虽然投影形式表面上彷佛被限制在了上述的类型里(int,long,single,double,decimal),可是若是咱们使用lambda表达式或匿名表达,投影的形式将容许较短的类型:
employees.Sum(e => e.Dependents);
employees.Sum(delegate(Employee e) { return e.Dependents; });
这是由于lambda表达式和匿名委托的结果能够自动扩大小数值类型(如 short)到 int。
Average()方法,就像SUM()同样,只不过它是用总和除以实际涉及到的项目数。涉及到的是什么意思?请记住,SUM( )不包括空值 。Average()是将全部非null值求平均。例如:
var intList = new int?[] { 10, 20, 30, null };
// 返回 20
Console.WriteLine(intList.Average());
MIN()扩展方法用于研究序列,并返回从它的最小值 :
MIN()支持几乎任何类型,只要该类型实现IComparable或IComparable <T>。所以,它是不限制的数值类型,能够用于任何比较的对象(包括像值类型的DateTime,TimeSpan):
var shortList = new short[] { 1, 3, 7, 9, -9, 33 };
// 返回 -9
var smallest = shortList.Min();
// 根据家庭成员数量找到最小值
var minDependents = employees.Min(e => e.Dependents);
此外,MIN()不使用泛型约束限制那些支持IComparable 接口的类型参数。相反,它抛出一个运行异常来回应若是序列非空,没有在它的对象实现IComparable的接口。
所以若是使用咱们的以前定义的Employee类,下面的第一次调用将返回Null(序列为空),第二次调用会抛出(非空,但不包含IComparable的对象序列) 。
var result1 = Enumerable.Empty<Employee>().Min();
var result2 = employees.Min();
var result3 = Enumerable.Empty<int>().Min();
var result4 = Enumerable.Empty<Employee>().Min(e => e.Dependents);
MAX()MIN()的行为彻底同样,只不过它返回最大值,而不是最小值。所以,咱们可使用这些序列中的最大值,或从一个序列的预测最大值:
///返回33
VAR biggestShort = shortList.Max();
//返回75250.0
VAR highestSalary = employees.Max(E => e.Salary);
其余方面,请参考Min()。
有三种形式的Aggregate():
这可能看起来至关复杂。只要记住 “此方法的工做原理是对 source 中的每一个元素调用一次 func。 每次调用 func 时,都将传递序列中的元素和聚合值(做为 func 的第一个参数)。 并用 func 的结果替换之前的聚合值。”
例如,若是咱们想要作一个序列中的全部数字的乘法:
var numbers = new int[] { 1, 3, 9, 2 };
// 使用当前总值乘如下一个数值获得新的总值
var product = numbers.Aggregate((total, next) => total * next);
最后的值是: 1 X 3 X 9 X 2 = 54。
下面看看怎么用更复杂的聚合计算, 可能咱们想获得这样一个结果 -- 用每一个雇员的工资除以家庭总人口数(包括他本身),再将这些数相加:
var weirdCalculation = employees.Aggregate(0.0,
(result, next) => result + next.Salary / (next.Dependents + 1));
参照上面的Empolyee 定义,获得的结果是 110458.8333, 为方便理解请看下面的Excel 表格:
因此你看,咱们能够作至关复杂的聚合计算,关键是要记住,你所提供的函数留给下一个“元素”,并把它应用到正在运行的“总值”。
四个简单的和一个可能有点复杂的,这一组功能至关强大!这些方法能够很容易地对序列进行聚合,使你不须要进行循环和本身计算。他们很运行快也很容易使用,他们很容易阅读,他们也被全面测试过了。敬请享受!