Enumerable.Aggregate() 是 Linq 的扩展方法,用于对集合序列进行累计操作。第一次使用时,可能有点摸不着头脑。
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
this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func
)
反编译一下,很容易看明白。
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 result = strs.Aggregate((s, next) =>
{
return next.Length > s.Length ? next : s;
});
Console.WriteLine("Max: {0}", result);
输出:
Max: cccc
除此之外,我们还可以给定一个初始值 (Seed)。
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func
)
和上面不同的是,这个重载方法将 seed 作为初始化累计结果。
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 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
另外一个重载,可以对累计结果做出更多的处理。
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 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 可以用来执行一个存储了算法委托集合的算法链。
{
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!