Aggregate是LINQ中可以自定义功能的聚合函数,该函数输入一个可枚举的序列,输出单个值。在微软的官方文档中给出了三个重载,分别如下:
public static TSource Aggregate<TSource> (this System.Collections.Generic.IEnumerable<TSource> source,
Func<TSource,TSource,TSource> func);
其中:
TSource
指出参数source中元素的类型。TSource
指出累加器函数的参数类型,第三个TSource
指出累加器函数的返回值类型使用Aggregate对元素进行求和,这里给出了三种方式
private static int Add(int x, int y){return x + y;}
void Main()
{
var numbers = new List<int> { 6, 2, 8, 3 };
// 方式一
int sum1 = numbers.Aggregate(func: (result, item) => result + item);
System.Console.WriteLine("Method 1: " + sum1);
// 方式二
int sum2 = numbers.Aggregate(func: Add);
System.Console.WriteLine("Method 2: " + sum2);
// 方式三
int sum3 = Enumerable.Aggregate<int>(numbers, func:(result, item) => result + item);
System.Console.WriteLine("Method 3: " + sum3);
}
结果:
Method 1: 19
Method 2: 19
Method 3: 19
为了进一步分析累加器函数是如何工作的,对上面的方式三进行修改,如下:
int sum3 = Enumerable.Aggregate<int>(numbers, func: (result, item) =>
{
System.Console.WriteLine("Result: " + result + ", Item: " + item);
return result + item;
});
结果:
Result: 6, Item: 2
Result: 8, Item: 8
Result: 16, Item: 3
由输出可以得出以下信息:
public static TSource Aggregate<TSource>( this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func)
{
if (source == null) throw Error.ArgumentNull("source");
if (func == null) throw Error.ArgumentNull("func");
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext()) throw Error.NoElements();
TSource result = e.Current;
while (e.MoveNext()) {
result = func(result, e.Current);
}
return result;
}
}
该重载相对于上一个仅仅是给累加器增加了一个初始值。但该初始值的类型可以与列表元素的类型不同。上一个函数可以看作该函数的特殊版本,累加器的输入参数类型与返回值类型相同
public static TAccumulate Aggregate<TSource,TAccumulate> (this System.Collections.Generic.IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate,TSource,TAccumulate> func);
其中:
TSource
指出参数source中元素的类型。TAccumulate
指出累加器函数的第一个参数与返回值的类型,第二个参数TSource
对应于要执行累加功能的序列的元素类型这里同样使用计算列表中元素合的方式。
private static int Add(int x, int y){return x + y;}
void Main()
{
var numbers = new List<int> { 6, 2, 8, 3 };
// 方式一
int sum1 = numbers.Aggregate(seed: 0, func: (result, item) => result + item);
System.Console.WriteLine("Method 1: " + sum1);
// 方式二
int sum2 = numbers.Aggregate(seed: 0, func: Add);
System.Console.WriteLine("Method 2: " + sum2);
// 方式三
int sum3 = Enumerable.Aggregate<int, int>(source: numbers,
seed: 0,
func:(result, item) => result + item);
System.Console.WriteLine("Method 3: " + sum3);
}
结果:
Method 1: 19
Method 2: 19
Method 3: 19
为了进一步分析累加器函数是如何工作的,对上面的方式三进行修改,如下:
int sum3 = Enumerable.Aggregate<int, int>(source: numbers, seed: 0, func: (result, item) =>
{
System.Console.WriteLine("Result: " + result + ", Item: " + item);
return result + item;
});
结果:
Result: 0, Item: 6
Result: 6, Item: 2
Result: 8, Item: 8
Result: 16, Item: 3
由输出可以得出以下信息:
void Main()
{
var numbers = new List<int> { 6, 2, 8, 3 };
double sum = Enumerable.Aggregate<int, double>(source: numbers, seed: 0D, func: (result, item) =>
{
System.Console.WriteLine("Result Type: " + result.GetType() + ", Result: " + result + ", Item: " + item);
return result + item;
});
System.Console.WriteLine("Method 3: " + sum);
}
结果:
Result Type: System.Double, Result: 0, Item: 6
Result Type: System.Double, Result: 6, Item: 2
Result Type: System.Double, Result: 8, Item: 8
Result Type: System.Double, Result: 16, Item: 3
Method 3: 19
计算班级中所有学生的年龄总和。
var students = new[]
{
new Student() {Name="张三", Age = 20},
new Student() {Name="李四", Age = 21},
new Student() {Name="王五", Age = 22},
new Student() {Name="赵六", Age = 23}
};
int sum = Enumerable.Aggregate<Student, int>(source: students, seed: 0, func: (result, item) =>
{
System.Console.WriteLine("Result Type: " + result.GetType() + ", Result: " + result + ", Item.Age: " + item.Age);
return result + item.Age;
});
System.Console.WriteLine("Method 3: " + sum);
结果:
Result Type: System.Int32, Result: 0, Item.Age: 20
Result Type: System.Int32, Result: 20, Item.Age: 21
Result Type: System.Int32, Result: 41, Item.Age: 22
Result Type: System.Int32, Result: 63, Item.Age: 23
Method 3: 86
该累加函数的返回结果的类型,可以既不与列表中元素的类型相同,也不与累加器初始值的类型相同。
public static TResult Aggregate<TSource,TAccumulate,TResult> (this System.Collections.Generic.IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate,TSource,TAccumulate> func,
Func<TAccumulate,TResult> resultSelector);
计算班级内学生的平均年龄
class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
void Main()
{
var students = new[]
{
new Student() {Name="张三", Age = 20},
new Student() {Name="李四", Age = 21},
new Student() {Name="王五", Age = 22},
new Student() {Name="赵六", Age = 23}
};
double sum = Enumerable.Aggregate<Student, int, double>(
source: students,
seed: 0,
func: (result, item) =>
{
System.Console.WriteLine("Result Type: " + result.GetType() + ", Result: " + result + ", Item.Age: " + item.Age);
return result + item.Age;
},
resultSelector: result =>
{
System.Console.WriteLine("=======================================");
System.Console.WriteLine("ResultSelector Parameter: " + result);
return (double)result / students.Length;
});
System.Console.WriteLine("Average Age: " + sum);
}
结果:
Result Type: System.Int32, Result: 0, Item.Age: 20
Result Type: System.Int32, Result: 20, Item.Age: 21
Result Type: System.Int32, Result: 41, Item.Age: 22
Result Type: System.Int32, Result: 63, Item.Age: 23
=======================================
ResultSelector Parameter: 86
Average Age: 21.5
public static TResult Aggregate<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector)
{
if (source == null) throw Error.ArgumentNull("source");
if (func == null) throw Error.ArgumentNull("func");
if (resultSelector == null) throw Error.ArgumentNull("resultSelector");
TAccumulate result = seed;
foreach (TSource element in source) {
result = func(result, element);
}
return resultSelector(result);
}