LINQ聚合算法解释
LINQ聚合算法解释
这听起来可能有点乏味,但是我还没有找到一个真正好的关于Aggregate
的解释。
好的解释应该是简洁、明确、全面的,并有一个小而清晰的例子。
具体取决于你所谈论的是哪种过载,但基本思想是:
- 从一个种子值开始作为“当前值”
- 迭代整个序列。对于序列中的每个值:
- 应用用户指定的函数将
(currentValue,sequenceValue)
转换为(nextValue)
- 设置
currentValue = nextValue
- 应用用户指定的函数将
- 返回最终的
currentValue
您可能会发现我在Edulinq系列中的Aggregate
帖子非常有用-它包括更详细的描述(包括各种过载)和实现。
一个简单的例子是使用Aggregate
作为Count
的替代方法:
// 0 is the seed, and for each item, we effectively increment the current value. // In this case we can ignore "item" itself. int count = sequence.Aggregate(0, (current, item) => current + 1);
或者将字符串序列中所有字符串的长度相加:
int total = sequence.Aggregate(0, (current, item) => current + item.Length);
个人而言,我很少觉得Aggregate
有用-“定制”的聚合方法通常对我来说已经足够好了。
聚合操作
最容易理解的定义是它对列表中的每个元素执行一个操作,考虑之前执行的操作。也就是说,它对第一个和第二个元素执行操作,并将结果向前传递。然后它对先前的结果和第三个元素执行操作,以此类推。
例1.求和
var nums = new[]{1,2,3,4}; var sum = nums.Aggregate( (a,b) => a + b); Console.WriteLine(sum); // output: 10 (1+2+3+4)
这将1
和2
相加得到3
。然后将3
(前一个结果)和3
(序列中的下一个元素)相加得到6
。然后将6
和4
相加得到10
。
例2.从字符串数组创建csv
var chars = new []{"a","b","c","d"}; var csv = chars.Aggregate( (a,b) => a + ',' + b); Console.WriteLine(csv); // Output a,b,c,d
这个例子的工作方式很相似。将a
与逗号和b
连接起来,得到a,b
。然后将a,b
与逗号和c
连接起来,得到a,b,c
。以此类推。
例3.使用初始值乘以数字
为了完整起见,Aggregate
有一个接受种子值的重载版本。
var multipliers = new []{10,20,30,40}; var multiplied = multipliers.Aggregate(5, (a,b) => a * b); Console.WriteLine(multiplied); //Output 1200000 ((((5*10)*20)*30)*40)
与上面的例子类似,这个例子从一个值5
开始,并将其乘以序列的第一个元素10
,得到一个结果50
。这个结果被沿着序列传递,并乘以序列中的下一个数字20
,得到一个结果1000
。这将继续执行剩下的两个序列元素。
在线示例:http://rextester.com/ZXZ64749
文档:http://msdn.microsoft.com/en-us/library/bb548651.aspx
附加说明
以上示例2使用字符串连接创建了由逗号分隔的值列表。这只是解释使用Aggregate
的一种简单方式,这也是本答案的意图。然而,如果使用此技术实际上创建大量逗号分隔的数据,更适合使用StringBuilder
,并且完全兼容使用种子重载来初始化StringBuilder
的Aggregate
。
var chars = new []{"a","b","c", "d"}; var csv = chars.Aggregate(new StringBuilder(), (a,b) => { if(a.Length>0) a.Append(","); a.Append(b); return a; }); Console.WriteLine(csv);