您的位置:首页 > 其它

[Linq] Enumerable.Aggregate[转载]

2012-07-30 11:21 141 查看
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!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: