[Linq] Enumerable.Aggregate[转载]

Enumerable.Aggregate() 是 Linq 的扩展方法,用于对集合序列进行累计操作。第一次使用时,可能有点摸不着头脑。

var ints = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

var result = ints.Aggregate((total, next) =>
{
  Console.WriteLine("total:{0}, next:{1}", total, next);
  return total + next;
});

Console.WriteLine(result);


输出:
total:1, next:2
total:3, next:3
total:6, next:4
total:10, next:5
total:15, next:6
total:21, next:7
total:28, next:8
total:36, next:9
45

public static TSource Aggregate<TSource>(
  this IEnumerable<TSource> source,
  Func<TSource, TSource, TSource> func
)


反编译一下,很容易看明白。

public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, 
  Func<TSource, TSource, TSource> func)
{
  // ... 省略部分代码 ...

  using (IEnumerator<TSource> enumerator = source.GetEnumerator())
  {
    if (!enumerator.MoveNext())
    {
      throw Error.NoElements();
    }

    TSource current = enumerator.Current;

    while (enumerator.MoveNext())
    {
      current = func(current, enumerator.Current);
    }

    return current;
  }
}


获取迭代器,提取第一个元素作为初始化累计结果,然后循环遍历其他元素,并依次调用 func 委托进行累计操作。func 有两个参数,第一个参数为上一次 func 的执行结果,第二个参数为要处理的集合元素。当然,我们并不一定要完成统计操作,也可以返回某单次 func 执行结果。

演示: 找回最长的字符串

var strs = new[] { "a", "bb", "cccc", "ddd" };

var result = strs.Aggregate((s, next) =>
{
  return next.Length > s.Length ? next : s;
});

Console.WriteLine("Max: {0}", result);


输出:
Max: cccc

除此之外,我们还可以给定一个初始值 (Seed)。

public static TAccumulate Aggregate<TSource, TAccumulate>(
  this IEnumerable<TSource> source,
  TAccumulate seed,
  Func<TAccumulate, TSource, TAccumulate> func
)


和上面不同的是,这个重载方法将 seed 作为初始化累计结果。

public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, 
  TAccumulate seed, 
  Func<TAccumulate, TSource, TAccumulate> func)
{
  // ... 省略部分代码 ...

  TAccumulate local = seed;

  foreach (TSource local2 in source)
  {
    local = func(local, local2);
  }

  return local;
}


我们修改一下上面的例子,查找最大的字符串长度。我们提供了一个初始化 seed,也就是说第一次传递给 func 的 maxLength = 3。

var strs = new[] { "a", "bb", "cccc", "ddd" };

var result = strs.Aggregate(3, (maxLength, next) =>
{
  Console.WriteLine("maxLength:{0}, next:{1}", maxLength, next);
  return next.Length > maxLength ? next.Length : maxLength;
});

Console.WriteLine("Max: {0}", result);


输出:
maxLength:3, next:a
maxLength:3, next:bb
maxLength:3, next:cccc
maxLength:4, next:ddd
Max: 4

另外一个重载,可以对累计结果做出更多的处理。

public static TResult Aggregate<TSource, TAccumulate, TResult>(
  this IEnumerable<TSource> source,
  TAccumulate seed,
  Func<TAccumulate, TSource, TAccumulate> func,
  Func<TAccumulate, TResult> resultSelector
)


无非是在返回结果以前多调用一个委托而已。

public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, 
  TAccumulate seed, 
  Func<TAccumulate, TSource, TAccumulate> func, 
  Func<TAccumulate, TResult> resultSelector)
{
  // ... 省略部分代码 ...

  TAccumulate local = seed;

  foreach (TSource local2 in source)
  {
    local = func(local, local2);
  }

  return resultSelector(local);
}

Func resultSelector 接收 func 的最后执行结果,执行一些特定逻辑后返回修正后的结果。

演示: 找出最长的字符串,并返回其大写结果。

var strs = new[] { "a", "bb", "cccc", "ddd" };

var result = strs.Aggregate("haa",
  (maxStr, next) =>
  {
    Console.WriteLine("maxStr:{0}, next:{1}", maxStr, next);
    return next.Length > maxStr.Length ? next : maxStr;
  },
  (maxStr) => 
  {
    return maxStr.ToUpper();
  });

Console.WriteLine("Max: {0}", result);


输出:
maxStr:haa, next:a
maxStr:haa, next:bb
maxStr:haa, next:cccc
maxStr:cccc, next:ddd
Max: CCCC

Aggregate 可以用来执行一个存储了算法委托集合的算法链。

var algorithms = new Func<string, string>[] 

   s => s + "1",
   s => s + "2",
   s => s + "3!",
   s => s + "4",
};

var result = algorithms.Aggregate("Hello, ", (s, a) => 
{
  if (s.EndsWith("!")) return s;
  return a(s);
});

Console.WriteLine(result);


输出:
Hello, 123!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值