Convert Sum to an Aggregate product expression
I have this expression:
group i by i.ItemId into g
select new
{
Id = g.Key,
Score = g.Sum(i => i.Score)
}).ToDictionary(o => o.Id, o => o.Score);
and in开发者_C百科stead of g.Sum
I'd like to get the mathematical product using Aggregate
.
To make sure it worked the same as .Sum
(but as product) I tried make an Aggregate function that would just return the sum...
Score = g.Aggregate(0.0, (sum, nextItem) => sum + nextItem.Score.Value)
However, this does not give the same result as using .Sum
. Any idas why?
nextItem.Score
is of type double?
.
public static class MyExtensions
{
public static double Product(this IEnumerable<double?> enumerable)
{
return enumerable
.Aggregate(1.0, (accumulator, current) => accumulator * current.Value);
}
}
The thing is that in your example you are starting the multiplication with 0.0 - A multiplication with zero yields zero, at the end the result will be zero.
Correct is to use the identity property of multiplication. While adding zero to a number leaves the number of unchanged, the same property holds true for a multiplication with 1. Hence, the correct way to start a product aggregate is to kick off multiplication wit the number 1.0.
If you aren't sure about initial value in your aggregate query and you don't acutally need one (like in this example) I would recommend you not to use it at all.
You can use Aggregate overload which doesn't take the initial value - http://msdn.microsoft.com/en-us/library/bb549218.aspx
Like this
int product = sequence.Aggregate((x, acc) => x * acc);
Which evaluates to item1 * (item2 * (item3 * ... * itemN))
.
instead of
int product = sequence.Aggregate(1.0, (x, acc) => x * acc);
Which evaluates to 1.0 * (item1 * (item2 * (item3 * ... * itemN)))
.
//edit: There is one important difference though. Former one does throw an InvalidOperationException when the input sequence is empty. Latter one returns seed value, therefore 1.0.
精彩评论