这听起来可能很蹩脚,但我还没能找到一个对聚合的真正好的解释。
好的意思是简短、描述性、全面,并有一个小而清晰的例子。
这听起来可能很蹩脚,但我还没能找到一个对聚合的真正好的解释。
好的意思是简短、描述性、全面,并有一个小而清晰的例子。
当前回答
一张图片胜过千言万语
提醒:Func<X, Y R> 是一个具有两个输入类型X和Y的函数,返回类型R的结果。
可枚举。聚合有三个重载:
过载1:
A Aggregate<A>(IEnumerable<A> a, Func<A, A, A> f)
例子:
new[]{1,2,3,4}.Aggregate((x, y) => x + y); // 10
这种过载很简单,但有以下限制:
序列必须包含至少一个元素,否则函数将抛出InvalidOperationException。元素和结果的类型必须相同。
过载2:
B Aggregate<A, B>(IEnumerable<A> a, B bIn, Func<B, A, B> f)
例子:
var hayStack = new[] {"straw", "needle", "straw", "straw", "needle"};
var nNeedles = hayStack.Aggregate(0, (n, e) => e == "needle" ? n+1 : n); // 2
这种过载更为普遍:
必须提供种子值(bIn)。集合可以是空的,在这种情况下,函数将产生种子值作为结果。元素和结果可以具有不同的类型。
过载3:
C Aggregate<A,B,C>(IEnumerable<A> a, B bIn, Func<B,A,B> f, Func<B,C> f2)
第三个过载不是很有用的IMO。通过使用重载2后跟一个转换其结果的函数,可以更简洁地编写相同的代码。
插图改编自这篇优秀的博客文章。
其他回答
这是关于在Fluent API(如Linq排序)上使用聚合的说明。
var list = new List<Student>();
var sorted = list
.OrderBy(s => s.LastName)
.ThenBy(s => s.FirstName)
.ThenBy(s => s.Age)
.ThenBy(s => s.Grading)
.ThenBy(s => s.TotalCourses);
让我们看看我们想要实现一个接受一组字段的排序函数,这很容易使用Aggregate而不是for循环,如下所示:
public static IOrderedEnumerable<Student> MySort(
this List<Student> list,
params Func<Student, object>[] fields)
{
var firstField = fields.First();
var otherFields = fields.Skip(1);
var init = list.OrderBy(firstField);
return otherFields.Skip(1).Aggregate(init, (resultList, current) => resultList.ThenBy(current));
}
我们可以这样使用:
var sorted = list.MySort(
s => s.LastName,
s => s.FirstName,
s => s.Age,
s => s.Grading,
s => s.TotalCourses);
一个简短而重要的定义可能是这样的:Linq Aggregate扩展方法允许声明一种应用于列表元素的递归函数,其操作数是两个:按元素在列表中的出现顺序排列的元素,一次一个元素,以及上一次递归迭代的结果,或者如果还没有递归,则什么都没有。
通过这种方式,您可以计算数字的阶乘,或连接字符串。
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、a、逗号和b连接起来形成a、b。然后用逗号和c连接a、b,形成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的结果。这将继续通过序列的其余2个元素。
现场示例:http://rextester.com/ZXZ64749文件:http://msdn.microsoft.com/en-us/library/bb548651.aspx
补遗
上面的示例2使用字符串串联来创建一个由逗号分隔的值列表。这是一种简单的方式来解释Aggregate的用法,而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);
更新示例:http://rextester.com/YZCVXV6464
这在一定程度上取决于你所说的过载,但基本的想法是:
以种子作为“当前值”开始重复序列。对于序列中的每个值:应用用户指定的函数将(currentValue,sequenceValue)转换为(nextValue)设置当前值=下一个值返回最终currentValue
你可能会发现我的Edulinq系列中的Aggregate文章很有用——它包含了更详细的描述(包括各种重载)和实现。
一个简单的例子是使用聚合作为计数的替代:
// 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);
就我个人而言,我很少发现聚合有用——“定制”的聚合方法通常对我来说足够好。
一张图片胜过千言万语
提醒:Func<X, Y R> 是一个具有两个输入类型X和Y的函数,返回类型R的结果。
可枚举。聚合有三个重载:
过载1:
A Aggregate<A>(IEnumerable<A> a, Func<A, A, A> f)
例子:
new[]{1,2,3,4}.Aggregate((x, y) => x + y); // 10
这种过载很简单,但有以下限制:
序列必须包含至少一个元素,否则函数将抛出InvalidOperationException。元素和结果的类型必须相同。
过载2:
B Aggregate<A, B>(IEnumerable<A> a, B bIn, Func<B, A, B> f)
例子:
var hayStack = new[] {"straw", "needle", "straw", "straw", "needle"};
var nNeedles = hayStack.Aggregate(0, (n, e) => e == "needle" ? n+1 : n); // 2
这种过载更为普遍:
必须提供种子值(bIn)。集合可以是空的,在这种情况下,函数将产生种子值作为结果。元素和结果可以具有不同的类型。
过载3:
C Aggregate<A,B,C>(IEnumerable<A> a, B bIn, Func<B,A,B> f, Func<B,C> f2)
第三个过载不是很有用的IMO。通过使用重载2后跟一个转换其结果的函数,可以更简洁地编写相同的代码。
插图改编自这篇优秀的博客文章。