定义
Aggregate扩展方法旨在对序列应用进行累加,它一共包含了3个重载方法,如下:
方法定义 | 方法说明 |
---|---|
Aggregate |
对序列应用累加器函数。 |
Aggregate |
对序列应用累加器函数。 将指定的种子值用作累加器初始值。 |
Aggregate |
对序列应用累加器函数。 将指定的种子值用作累加器的初始值,并使用指定的函数选择结果值。 |
Aggregate(IEnumerable, Func)
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (func == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.func);
}
//获取泛型版本的迭代器
using (IEnumerator<TSource> e = source.GetEnumerator())
{
//判断第一个值是否存在
if (!e.MoveNext())
{
ThrowHelper.ThrowNoElementsException();
}
//将第一个值赋予result
TSource result = e.Current;
//循环处理
while (e.MoveNext())
{
//第一次调用func时: 第一个参数是集合的第一个值,第二个参数是集合的第二个值
//第二次调用func时: 第一个参数是上一次func返回的值,第二个参数是集合的第三个值
//......
//第n次调用func时: 第一个参数依然是上一次func返回的值,第二个参数是集合的第n+1个值
result = func(result, e.Current);
}
//如果集合只有一个元素,直接返回第一个值
//如果集合超过一个元素,按上面的逻辑依次调用func后返回的最终值
return result;
}
}
//示例1
string[] strs = new string[] { "I","am","happy","to","share" };
string sentence = strs.Aggregate((str1, str2) => str1 + " " + str2);
//output: I am happy to share
//示例2
int[] nums = new int[] { 1,2,3,4,5 };
int count = nums.Aggregate((num1, num2) => num1 + num2);
//output: 15
Aggregate(IEnumerable, TAccumulate, Func)
public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (func == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.func);
}
TAccumulate result = seed;
foreach (TSource element in source)
{
//第一次调用func时: 第一个参数是seed参数,第二个参数是集合的第一个值
//第二次调用func时: 第一个参数是上一次func返回的值,第二个参数是集合的第二个值
//......
//第n次调用func时: 第一个参数依然是上一次func返回的值,第二个参数是集合的第n个值
result = func(result, element);
}
return result;
}
/// <summary>
/// 定义一个类,包含花费的日期和购物花费、房租
/// </summary>
public class Expenses
{
/// <summary>
/// 日期
/// </summary>
public DateOnly Date { get; set; }
/// <summary>
/// 购物花费
/// </summary>
public decimal Shopping { get; set; }
/// <summary>
/// 房租
/// </summary>
public decimal Rent { get; set; }
}
//初始化一些数据
List<Expenses> expenses = new List<Expenses>()
{
new Expenses(){ Date = DateOnly.Parse("2023-03-29"), Shopping = 50, Rent = 0 },
new Expenses(){ Date = DateOnly.Parse("2023-03-30"), Shopping = 60, Rent = 0 },
new Expenses(){ Date = DateOnly.Parse("2023-03-31"), Shopping = 70, Rent = 1500 },
};
//此时我们想求出这三天每样花费的总计
{
//申明一个匿名变量,因为第一个传入的参数类型也是func的返回类型,所以我们都用decimal
var expenseCount = new { shopping = (decimal)0, rent = (decimal)0 };
//累加Shopping和Rent
expenseCount = expenses.Aggregate(expenseCount,
(expense1, expense2) =>
new {
shopping = expense1.shopping + expense2.Shopping,
rent = expense1.rent + expense2.Rent
}
);
//expenseCount:{"shopping":180,"rent":1500}
}
//当然,我们也可以实例化一个Expenses,循环执行方法的时候在里面属性直接叠加
//这样我们都不需要返回值了,因为返回值就是expenseCount本身
{
var expenseCount = new Expenses();
expenseCount = expenses.Aggregate(expenseCount,
(expense1, expense2) =>
{
expense1.Shopping += expense2.Shopping;
expense1.Rent += expense2.Rent;
return expense1;
}
);
//expenseCount: {"Date":"0001-01-01","Shopping":180,"Rent":1500}
}
Aggregate(IEnumerable, TAccumulate, Func, Func)
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)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (func == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.func);
}
if (resultSelector == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.resultSelector);
}
TAccumulate result = seed;
foreach (TSource element in source)
{
//第一次调用func时: 第一个参数是seed参数,第二个参数是集合的第一个值
//第二次调用func时: 第一个参数是上一次func返回的值,第二个参数是集合的第二个值
//......
//第n次调用func时: 第一个参数依然是上一次func返回的值,第二个参数是集合的第n个值
result = func(result, element);
}
//其实就是再对结果进行处理
return resultSelector(result);
}
//上一个示例的基础上我们想得到这三天总计的花费
var expenseCount = new Expenses();
decimal count = expenses.Aggregate(expenseCount,
(expense1, expense2) =>
{
expense1.Shopping += expense2.Shopping;
expense1.Rent += expense2.Rent;
return expense1;
},
ec => ec.Shopping+ec.Rent
);
//ec其实就代表了叠加到最后的expenseCount
//count: 1680