Aggregate - 图1

定义

Aggregate扩展方法旨在对序列应用进行累加,它一共包含了3个重载方法,如下:

方法定义 方法说明
Aggregate(IEnumerable, Func))-system-func((-0-0-0)))) 对序列应用累加器函数。
Aggregate(IEnumerable, TAccumulate, Func))-1-system-func((-1-0-1)))) 对序列应用累加器函数。 将指定的种子值用作累加器初始值。
Aggregate(IEnumerable, TAccumulate, Func, Func))-1-system-func((-1-0-1))-system-func((-1-2)))) 对序列应用累加器函数。 将指定的种子值用作累加器的初始值,并使用指定的函数选择结果值。

Aggregate(IEnumerable, Func)

  1. public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
  2. {
  3. if (source == null)
  4. {
  5. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
  6. }
  7. if (func == null)
  8. {
  9. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.func);
  10. }
  11. //获取泛型版本的迭代器
  12. using (IEnumerator<TSource> e = source.GetEnumerator())
  13. {
  14. //判断第一个值是否存在
  15. if (!e.MoveNext())
  16. {
  17. ThrowHelper.ThrowNoElementsException();
  18. }
  19. //将第一个值赋予result
  20. TSource result = e.Current;
  21. //循环处理
  22. while (e.MoveNext())
  23. {
  24. //第一次调用func时: 第一个参数是集合的第一个值,第二个参数是集合的第二个值
  25. //第二次调用func时: 第一个参数是上一次func返回的值,第二个参数是集合的第三个值
  26. //......
  27. //第n次调用func时: 第一个参数依然是上一次func返回的值,第二个参数是集合的第n+1个值
  28. result = func(result, e.Current);
  29. }
  30. //如果集合只有一个元素,直接返回第一个值
  31. //如果集合超过一个元素,按上面的逻辑依次调用func后返回的最终值
  32. return result;
  33. }
  34. }
  1. //示例1
  2. string[] strs = new string[] { "I","am","happy","to","share" };
  3. string sentence = strs.Aggregate((str1, str2) => str1 + " " + str2);
  4. //output: I am happy to share
  5. //示例2
  6. int[] nums = new int[] { 1,2,3,4,5 };
  7. int count = nums.Aggregate((num1, num2) => num1 + num2);
  8. //output: 15

Aggregate(IEnumerable, TAccumulate, Func)

  1. public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
  2. {
  3. if (source == null)
  4. {
  5. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
  6. }
  7. if (func == null)
  8. {
  9. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.func);
  10. }
  11. TAccumulate result = seed;
  12. foreach (TSource element in source)
  13. {
  14. //第一次调用func时: 第一个参数是seed参数,第二个参数是集合的第一个值
  15. //第二次调用func时: 第一个参数是上一次func返回的值,第二个参数是集合的第二个值
  16. //......
  17. //第n次调用func时: 第一个参数依然是上一次func返回的值,第二个参数是集合的第n个值
  18. result = func(result, element);
  19. }
  20. return result;
  21. }
  1. /// <summary>
  2. /// 定义一个类,包含花费的日期和购物花费、房租
  3. /// </summary>
  4. public class Expenses
  5. {
  6. /// <summary>
  7. /// 日期
  8. /// </summary>
  9. public DateOnly Date { get; set; }
  10. /// <summary>
  11. /// 购物花费
  12. /// </summary>
  13. public decimal Shopping { get; set; }
  14. /// <summary>
  15. /// 房租
  16. /// </summary>
  17. public decimal Rent { get; set; }
  18. }
  19. //初始化一些数据
  20. List<Expenses> expenses = new List<Expenses>()
  21. {
  22. new Expenses(){ Date = DateOnly.Parse("2023-03-29"), Shopping = 50, Rent = 0 },
  23. new Expenses(){ Date = DateOnly.Parse("2023-03-30"), Shopping = 60, Rent = 0 },
  24. new Expenses(){ Date = DateOnly.Parse("2023-03-31"), Shopping = 70, Rent = 1500 },
  25. };
  26. //此时我们想求出这三天每样花费的总计
  27. {
  28. //申明一个匿名变量,因为第一个传入的参数类型也是func的返回类型,所以我们都用decimal
  29. var expenseCount = new { shopping = (decimal)0, rent = (decimal)0 };
  30. //累加Shopping和Rent
  31. expenseCount = expenses.Aggregate(expenseCount,
  32. (expense1, expense2) =>
  33. new {
  34. shopping = expense1.shopping + expense2.Shopping,
  35. rent = expense1.rent + expense2.Rent
  36. }
  37. );
  38. //expenseCount:{"shopping":180,"rent":1500}
  39. }
  40. //当然,我们也可以实例化一个Expenses,循环执行方法的时候在里面属性直接叠加
  41. //这样我们都不需要返回值了,因为返回值就是expenseCount本身
  42. {
  43. var expenseCount = new Expenses();
  44. expenseCount = expenses.Aggregate(expenseCount,
  45. (expense1, expense2) =>
  46. {
  47. expense1.Shopping += expense2.Shopping;
  48. expense1.Rent += expense2.Rent;
  49. return expense1;
  50. }
  51. );
  52. //expenseCount: {"Date":"0001-01-01","Shopping":180,"Rent":1500}
  53. }

Aggregate(IEnumerable, TAccumulate, Func, Func)

  1. public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
  2. {
  3. if (source == null)
  4. {
  5. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
  6. }
  7. if (func == null)
  8. {
  9. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.func);
  10. }
  11. if (resultSelector == null)
  12. {
  13. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.resultSelector);
  14. }
  15. TAccumulate result = seed;
  16. foreach (TSource element in source)
  17. {
  18. //第一次调用func时: 第一个参数是seed参数,第二个参数是集合的第一个值
  19. //第二次调用func时: 第一个参数是上一次func返回的值,第二个参数是集合的第二个值
  20. //......
  21. //第n次调用func时: 第一个参数依然是上一次func返回的值,第二个参数是集合的第n个值
  22. result = func(result, element);
  23. }
  24. //其实就是再对结果进行处理
  25. return resultSelector(result);
  26. }
  1. //上一个示例的基础上我们想得到这三天总计的花费
  2. var expenseCount = new Expenses();
  3. decimal count = expenses.Aggregate(expenseCount,
  4. (expense1, expense2) =>
  5. {
  6. expense1.Shopping += expense2.Shopping;
  7. expense1.Rent += expense2.Rent;
  8. return expense1;
  9. },
  10. ec => ec.Shopping+ec.Rent
  11. );
  12. //ec其实就代表了叠加到最后的expenseCount
  13. //count: 1680