使用第一对作为种子聚合

时间:2013-11-25 08:22:12

标签: c# linq aggregate

有没有办法聚合(折叠)这个序列

{ a, b, c, d }

使用函数f(x,y)这样我最终得到f(f(f(a,b),c),d)

result = f(a,b)
result = f(result, c)
result = f(result, d)

目前我这样做(假设列表长度为> = 2):

var seed = f(list[0], list[1]);
var result = list.Skip(2).Aggregate(seed, f);

我可以在单个表达式中表达相同的内容吗?

编辑:假设f的结果类型与元素类型相同,并且f没有好的“零元素”,即良好的种子价值,f(0, a) = a。具有零元素的操作的示例是加法(零元素= 0),乘法(零元素= 1),列表连接(零元素= [])。

没有良好零元素的操作的例子是平均值,即

result = avg(a,b)
result = avg(result, c)
result = avg(result, d)

此折叠的唯一有效种子是avg(a,a)avg(a,b)。所以对于函数avg和输入序列{a, b, c, d}我想result = avg(avg(avg(a,b),c),d)

2 个答案:

答案 0 :(得分:3)

在这种情况下你不需要任何种子,尝试聚合函数的this重载:

var result = list.Aggregate((a,b)=>f(a,b));

答案 1 :(得分:3)

Aggregate已将聚合函数应用于第一对,因此您不需要将它们分开:

var result = list.Aggregate((a,b) => f(a,b));

但是,如果累积值的类型与集合元素的类型不同,则您无法使用上面的重载(这可能就是您提出此问题的原因)。您可以从种子值开始,#0;零"这允许您仅从第一个元素开始,并且不需要Skip

Func<int, string, int> f = (a, b) => a + b.Length;
var list = new[] { "1", "12", "123", "1234" };
var seed = 0;
var result = list.Aggregate(seed, (a, b) => f(a, b));