标签:
LINQ provides several aggregation extension methods: Aggregate, Average, Count, LongCount, Max, Min and Sum. The aggregation methods all take a list of objects and reduces that list to a single result. Conceptually it helps to think of Aggregate as a generic building block and the others aggregation methods (Average, Max, etc.) as special cases of Aggregate. In functional programming languages, such as F#, Aggregate is usually named fold (or inject in Ruby). The SQL like name Aggregate leads developers to write off Aggregate as purely for numeric aggregation purposes. In fact, Aggregate can be used whenever we want to build a single object from a group of objects.
Looking at the Aggregate method signature is a pretty scary experience:
public static TAccumulate Aggregate<TSource, TAccumulate>( this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func )
The Aggregate methods takes a list of source objects, a seed value and an accumulator function which it processes as follows:
This can take some getting your head around. Here is an example:
var whiskeyNames = new [] {"Ardbeg 1998", "Glenmorangie","Talisker", "Cragganmore"}; var listOfWhiskies = whiskeyNames.Aggregate("Whiskies: ", (accumulated, next) => { Console.Out.WriteLine("(Adding [{0}] to the list [{1}])", next, accumulated); return accumulated + " " + next; }); Console.Out.WriteLine(listOfWhiskies);
This outputs:
(Adding [Ardbeg 1998] to the list [Whiskies: ]) (Adding [Glenmorangie] to the list [Whiskies: Ardbeg 1998]) (Adding [Talisker] to the list [Whiskies: Ardbeg 1998 Glenmorangie]) (Adding [Cragganmore] to the list [Whiskies: Ardbeg 1998 Glenmorangie Talisker]) Whiskies: Ardbeg 1998 Glenmorangie Talisker Cragganmore
The seed parameter is optional. If it is omitted the first two items in the list will be passed to the function, as this example demonstrates:
listOfWhiskies = whiskeyNames.Aggregate((accumulated, next) => { Console.Out.WriteLine("(Adding [{0}] to the list [{1}])", next, accumulated); return accumulated + " " + next; }); Console.Out.WriteLine(listOfWhiskies);
This outputs:
(Adding [Glenmorangie] to the list [Ardbeg 1998]) (Adding [Talisker] to the list [Ardbeg 1998 Glenmorangie]) (Adding [Cragganmore] to the list [Ardbeg 1998 Glenmorangie Talisker]) Ardbeg 1998 Glenmorangie Talisker Cragganmore
Whiskey mostExpensiveWhiskey = whiskies.Aggregate((champion, challenger) => challenger.Price > champion.Price ? challenger : champion); Console.WriteLine("Most expensive is {0}", mostExpensiveWhiskey.Name);
var blendedWhiskey = whiskies.Where(x=> x.Country == "Scotland") .Aggregate(new Whiskey() { Name="Tesco value whiskey", Age=3, Country="Scotland" }, (newWhiskey, nextWhiskey) => { newWhiskey.Ingredients.Add(nextWhiskey); newWhiskey.Price += (nextWhiskey.Price / 10); return newWhiskey; });
// 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);
var nums = new[]{1,2,3,4};
var sum = nums.Aggregate( (a,b) => a + b);
Console.WriteLine(sum); // output: 10 (1+2+3+4)
Note:
the aggregate result type an seed type is the same. You can use lambda expresion or lambda statement(need return) as accumulate function.
Reference:
1. Refactoring to LINQ Part 2: Aggregate is Great
2. LINQ Aggregate algorithm explained
标签:
原文地址:http://www.cnblogs.com/liao-hua/p/4575725.html