LINQ聚合算法解释
这可能听起来很蹩脚,但我还没有找到对Aggregate
真正好的解释。
好的意味着简短、描述性、全面,并有一个小而清晰的例子。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
这可能听起来很蹩脚,但我还没有找到对Aggregate
真正好的解释。
好的意味着简短、描述性、全面,并有一个小而清晰的例子。
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(12)
聚合主要用于对数据进行分组或求和。
根据 MSDN
“聚合函数对序列应用累加器函数。”
示例 1:将数组中的所有数字相加。
*重要提示:默认情况下,初始聚合值是集合序列中的第 1 个元素。
即:total变量初始值默认为1。
变量解释
total:它将保存func返回的总和值(聚合值)。
nextValue:它是数组序列中的下一个值。然后将该值添加到聚合值(即总计)中。
示例 2:添加数组中的所有项目。还设置初始累加器值从 10 开始相加。
参数说明:
第一个参数是初始值(起始值,即种子值),它将用于开始与数组中的下一个值相加。
第二个参数是一个 func,它是一个需要 2 个 int 的 func。
1.total:计算后 func 返回的总和值(聚合值)与之前相同。
2.nextValue: :它是数组序列中的下一个值。然后将该值添加到聚合值(即总计)中。
此外,调试此代码将使您更好地了解聚合的工作原理。
Aggregate is basically used to Group or Sum up data.
According to MSDN
"Aggregate Function Applies an accumulator function over a sequence."
Example 1: Add all the numbers in a array.
*important: The initial aggregate value by default is the 1 element in the sequence of collection.
i.e: the total variable initial value will be 1 by default.
variable explanation
total: it will hold the sum up value(aggregated value) returned by the func.
nextValue: it is the next value in the array sequence. This value is than added to the aggregated value i.e total.
Example 2: Add all items in an array. Also set the initial accumulator value to start adding with from 10.
arguments explanation:
the first argument is the initial(starting value i.e seed value) which will be used to start addition with the next value in the array.
the second argument is a func which is a func that takes 2 int.
1.total: this will hold same as before the sum up value(aggregated value) returned by the func after the calculation.
2.nextValue: : it is the next value in the array sequence. This value is than added to the aggregated value i.e total.
Also debugging this code will give you a better understanding of how aggregate work.
除了这里已经提供的所有精彩答案之外,我还使用它来引导项目完成一系列转换步骤。
如果转换作为
Func
实现,您可以将多个转换添加到List>
并使用聚合
以遍历T
的实例完成每个步骤。更具体的示例
您想要获取一个
string
值,并让它完成一系列可以通过编程方式构建的文本转换。这将创建一系列转换:删除前导和尾随空格 ->删除第一个字符 ->删除最后一个字符 ->转换为大写。可以根据需要添加、删除或重新排序此链中的步骤,以创建所需的任何类型的转换管道。
此特定管道的最终结果是
" cat "
变为"A"
。一旦您意识到
T
可以是任何东西,这就会变得非常强大。这可以用于图像转换,例如滤镜,以 BitMap 为例;In addition to all the great answers here already, I've also used it to walk an item through a series of transformation steps.
If a transformation is implemented as a
Func<T,T>
, you can add several transformations to aList<Func<T,T>>
and useAggregate
to walk an instance ofT
through each step.A more concrete example
You want to take a
string
value, and walk it through a series of text transformations that could be built programatically.This will create a chain of transformations: Remove leading and trailing spaces -> remove first character -> remove last character -> convert to upper-case. Steps in this chain can be added, removed, or reordered as needed, to create whatever kind of transformation pipeline is required.
The end result of this specific pipeline, is that
" cat "
becomes"A"
.This can become very powerful once you realize that
T
can be anything. This could be used for image transformations, like filters, usingBitMap
as an example;从Jamiec的回答中学到了很多东西。
如果唯一需要生成 CSV 字符串,你可以尝试这个。
这是一个使用 100 万个字符串的测试
源代码位于 此处
Learned a lot from Jamiec's answer.
If the only need is to generate CSV string, you may try this.
Here is a test with 1 million strings
Source code is here
聚合方法是泛型集合的扩展方法。聚合方法将函数应用于集合的每个项目。不仅应用一个函数,还将其结果作为下一次迭代的初始值。因此,我们将从集合中获得计算值(最小值、最大值、平均值或其他统计值)。
因此,聚合方法是递归函数的一种安全实现形式。
安全,因为递归会迭代集合中的每一项,而我们无法得到任何无穷大由于错误的退出条件而导致循环暂停。 递归,因为当前函数的结果被用作下一个函数调用的参数。
工作原理:
它与此函数执行相同的操作:
Aggregate method is an extension method for generic collections. Aggregate method applies a function to each item of a collection. Not just only applies a function, but takes its result as initial value for the next iteration. So, as a result, we will get a computed value (min, max, avg, or other statistical value) from a collection.
Therefore, Aggregate method is a form of safe implementation of a recursive function.
Safe, because the recursion will iterate over each item of a collection and we can’t get any infinite loop suspension by wrong exit condition. Recursive, because the current function’s result is used as a parameter for the next function call.
How it works:
which is doing the same thing as this function:
这是关于在 Fluent API(例如 Linq 排序)上使用
Aggregate
的说明。让我们看看我们想要实现一个接受一组字段的排序函数,使用
Aggregate
而不是for循环非常容易,如下所示:我们可以这样使用它:
This is an explanation about using
Aggregate
on a Fluent API such as Linq Sorting.and lets see we want to implement a sort function that take a set of fields, this is very easy using
Aggregate
instead of a for-loop, like this:And we can use it like this:
用于对多维整数数组中的列求和的聚合
在聚合函数中使用带索引的 Select 对匹配的列求和并返回一个新数组; { 3 + 2 = 5, 1 + 4 = 5, 7 + 16 = 23, 8 + 5 = 13 }。
但是计算布尔数组中 true 的数量更加困难,因为累积类型 (int) 与源类型 (bool) 不同;这里需要一个种子才能使用第二个重载。
Aggregate used to sum columns in a multi dimensional integer array
Select with index is used within the Aggregate func to sum the matching columns and return a new Array; { 3 + 2 = 5, 1 + 4 = 5, 7 + 16 = 23, 8 + 5 = 13 }.
But counting the number of trues in a Boolean array is more difficult since the accumulated type (int) differs from the source type (bool); here a seed is necessary in order to use the second overload.
大家都给出了自己的解释。我的解释是这样的。
聚合方法将函数应用于集合的每个项目。例如,让我们有集合 { 6, 2, 8, 3 } 和函数 Add (operator +) 它执行 (((6+2)+8)+3) 并返回 19
在这个例子中,传递了命名方法 Add而不是 lambda 表达式。
Everyone has given his explanation. My explanation is like that.
Aggregate method applies a function to each item of a collection. For example, let's have collection { 6, 2, 8, 3 } and the function Add (operator +) it does (((6+2)+8)+3) and returns 19
In this example there is passed named method Add instead of lambda expression.
一个简短而重要的定义可能是这样的:Linq Aggregate 扩展方法允许声明一种应用于列表元素的递归函数,其操作数有两个:元素按照它们出现在列表中的顺序,一次一个元素,以及前一个递归迭代的结果,或者如果尚未递归则什么也没有。
通过这种方式,您可以计算数字的阶乘,或连接字符串。
A short and essential definition might be this: Linq Aggregate extension method allows to declare a sort of recursive function applied on the elements of a list, the operands of whom are two: the elements in the order in which they are present into the list, one element at a time, and the result of the previous recursive iteration or nothing if not yet recursion.
In this way you can compute the factorial of numbers, or concatenate strings.
Aggregate
最容易理解的定义是,它对列表中的每个元素执行操作,同时考虑到之前进行的操作。也就是说,它对第一个和第二个元素执行操作并将结果向前推进。然后它对先前的结果和第三个元素进行运算并结转。 示例1. 对数字求和
将
1
和2
相加得到3
。然后添加3
(前一个元素的结果)和3
(序列中的下一个元素)以形成6
。然后添加6
和4
得到10
。示例 2. 从字符串数组创建 csv
这的工作方式大致相同。将
a
逗号和b
连接起来形成a,b
。然后将a,b
与逗号和c
连接起来,形成a,b,c
。等等。示例 3. 使用种子进行数字相乘
为了完整起见,有一个
与上面的示例非常相似,它以值
5
开头,并将其乘以序列10
的第一个元素,得到结果50
。该结果被结转并乘以序列20
中的下一个数字,得到结果1000
。这将继续到序列的剩余 2 个元素。实例:http://rextester.com/ZXZ64749
文档: http://msdn.microsoft.com/en-us/library/bb548651 .aspx
附录
上面的示例 2 使用字符串连接来创建以逗号分隔的值列表。这是解释聚合的使用的一种简单方法,这也是这个答案的目的。但是,如果使用此技术实际创建大量逗号分隔的数据,那么使用 StringBuilder 会更合适,并且这与使用 Aggregate 完全兼容用于启动 StringBuilder 的种子重载。
更新的示例:http://rextester.com/YZCVXV6464
The easiest-to-understand definition of
Aggregate
is that it performs an operation on each element of the list taking into account the operations that have gone before. That is to say it performs the action on the first and second element and carries the result forward. Then it operates on the previous result and the third element and carries forward. etc.Example 1. Summing numbers
This adds
1
and2
to make3
. Then adds3
(result of previous) and3
(next element in sequence) to make6
. Then adds6
and4
to make10
.Example 2. create a csv from an array of strings
This works in much the same way. Concatenate
a
a comma andb
to makea,b
. Then concatenatesa,b
with a comma andc
to makea,b,c
. and so on.Example 3. Multiplying numbers using a seed
For completeness, there is an overload of
Aggregate
which takes a seed value.Much like the above examples, this starts with a value of
5
and multiplies it by the first element of the sequence10
giving a result of50
. This result is carried forward and multiplied by the next number in the sequence20
to give a result of1000
. This continues through the remaining 2 element of the sequence.Live examples: http://rextester.com/ZXZ64749
Docs: http://msdn.microsoft.com/en-us/library/bb548651.aspx
Addendum
Example 2, above, uses string concatenation to create a list of values separated by a comma. This is a simplistic way to explain the use of
Aggregate
which was the intention of this answer. However, if using this technique to actually create a large amount of comma separated data, it would be more appropriate to use aStringBuilder
, and this is entirely compatible withAggregate
using the seeded overload to initiate theStringBuilder
.Updated example: http://rextester.com/YZCVXV6464
它部分取决于您所讨论的重载,但基本思想是:
(currentValue,equenceValue)
转换为(nextValue)
currentValue = nextValue
您可能会找到 我的 Edulinq 系列中的
聚合
帖子很有用 - 它包含更详细的描述(包括各种重载)和实现。一个简单的示例是使用
Aggregate
作为Count
的替代方案:或者可能对字符串序列中的所有字符串长度求和:
就个人而言,我很少发现
Aggregate
有用 - “定制”聚合方法通常对我来说足够好了。It partly depends on which overload you're talking about, but the basic idea is:
(currentValue, sequenceValue)
into(nextValue)
currentValue = nextValue
currentValue
You may find the
Aggregate
post in my Edulinq series useful - it includes a more detailed description (including the various overloads) and implementations.One simple example is using
Aggregate
as an alternative toCount
:Or perhaps summing all the lengths of strings in a sequence of strings:
Personally I rarely find
Aggregate
useful - the "tailored" aggregation methods are usually good enough for me.超短
聚合的工作方式类似于 Haskell/ML/F# 中的折叠。
稍长
.Max()、.Min()、.Sum()、.Average() 都会迭代序列中的元素,并使用各自的聚合函数聚合它们。 .Aggregate() 是通用聚合器,它允许开发人员指定开始状态(也称为种子)和聚合函数。
我知道您要求简短的解释,但我认为其他人给出了一些简短的答案,我认为您可能会对稍长的答案感兴趣
带有代码的长版本
说明它的作用的一种方法是展示如何在使用 foreach 和使用 .Aggregate 时实现示例标准差。 注意:我在这里没有优先考虑性能,因此我不必要地对集合进行多次迭代
首先使用一个辅助函数来创建二次距离之和:
然后使用 ForEach 采样标准差:
然后使用 .Aggregate 一次:
请注意,除了如何计算 sumOfQuadraticDistance 之外,这些函数是相同的:
对比:
那么 .Aggregate 的作用是封装这个聚合器模式,我希望.Aggregate 的实现看起来像这样:
使用标准差函数看起来像这样:
恕我直言
那么 .Aggregate 有助于可读性吗?总的来说,我喜欢 LINQ,因为我认为 .Where、.Select、.OrderBy 等对可读性有很大帮助(如果您避免内联分层 .Selects)。出于完整性原因,Aggregate 必须位于 Linq 中,但我个人不太相信 .Aggregate 与编写良好的 foreach 相比增加了可读性。
Super short
Aggregate works like fold in Haskell/ML/F#.
Slightly longer
.Max(), .Min(), .Sum(), .Average() all iterates over the elements in a sequence and aggregates them using the respective aggregate function. .Aggregate () is generalized aggregator in that it allows the developer to specify the start state (aka seed) and the aggregate function.
I know you asked for a short explaination but I figured as others gave a couple of short answers I figured you would perhaps be interested in a slightly longer one
Long version with code
One way to illustrate what does it could be show how you implement Sample Standard Deviation once using foreach and once using .Aggregate. Note: I haven't prioritized performance here so I iterate several times over the colleciton unnecessarily
First a helper function used to create a sum of quadratic distances:
Then Sample Standard Deviation using ForEach:
Then once using .Aggregate:
Note that these functions are identical except for how sumOfQuadraticDistance is calculated:
Versus:
So what .Aggregate does is that it encapsulates this aggregator pattern and I expect that the implementation of .Aggregate would look something like this:
Using the Standard deviation functions would look something like this:
IMHO
So does .Aggregate help readability? In general I love LINQ because I think .Where, .Select, .OrderBy and so on greatly helps readability (if you avoid inlined hierarhical .Selects). Aggregate has to be in Linq for completeness reasons but personally I am not so convinced that .Aggregate adds readability compared to a well written foreach.
一张图胜过一千个字
Enumerable.Aggregate 具有三个重载:
重载 1:
示例:
这种重载很简单,但有以下限制:
否则该函数将抛出
InvalidOperationException
。重载 2:
示例:
这种重载更为通用:
bIn
)。在这种情况下,该函数将产生种子值作为结果。
重载 3:
在我看来,第三个重载并不是很有用。
通过使用重载 2,后跟一个转换其结果的函数,可以更简洁地编写相同的内容。
A picture is worth a thousand words
Enumerable.Aggregate has three overloads:
Overload 1:
Example:
This overload is simple, but it has the following limitations:
otherwise the function will throw an
InvalidOperationException
.Overload 2:
Example:
This overload is more general:
bIn
).in this case, the function will yield the seed value as result.
Overload 3:
The third overload is not very useful IMO.
The same can be written more succinctly by using overload 2 followed by a function that transforms its result.