LINQ Farm Seed 02: Aggregate Operator Part II
LINQ Farm Seeds are short posts designed to be read in a few minutes. In the previous seed we used the first overload of the C# 3.0 LINQ Aggregate operator to sum a list of numbers. In this post we'll work with a list of words.
The code we will look at reverses the following string:
- The end is the beginning, the beginning the end
If we pass this string in to our method, it will yield this result:
- end the beginning the beginning, the is end The
Here is the method that we will use:
private string ReverseSentence(string sentence)
{
string[] words = sentence.Split(' ');
return words.Aggregate((accumulator, b) => b + " " + accumulator);
}
The method first breaks the sentence down into a list of words:
string[] words = sentence.Split(' ');
It passes this list to the LINQ to Objects Aggregate operator. This overload of that operator takes a single lambda expression as a parameter. The lambda expression takes two parameters (accumulator, b) and returns them in reverse order (b accumulator). If it were a standard method rather than a lambda expression, it would look like this:
private static string Reverse(string accumulator, string b)
{
return b + " " + accumulator;
}
The method would be called like this:
words.Aggregate(Reverse);
In our code, however, we use lambda expressions rather than standard methods.
As you recall from the previous post, the Aggregate operators passes in items two at a time from a list. The first parameter becomes the accumulator for the aggregation. This is why I chose to give the first parameter in the lambda expression the name accumulator:
return words.Aggregate((accumulator, b) => b + " " + accumulator);
You can watch the aggregation process take place in the debugger. Set a breakpoint on the call to Aggregate, and add the variables accumulator and b to your watch list. Step through the method with the F11 key. You can watch the result "accumulate" in the accumulator variable.
The process begins by passing the first two words into the lambda expression, where the first one is the accumulator:
- (The) (end)
The method reverses their order and places a space between them:
- end The
The next iteration sends in the result of the previous expression, plus the next word from the list:
- (end the) (is)
The lambda expression reverses them:
- is end The
The Aggregate operator now processes the result of the previous iteration in the accumulator plus the next word:
- (is end The) (the)
Again our lambda expression swaps the parameters and places a space between them:
- the is end The
Next time we pass in the following:
- (the is end The) (beginning,)
This yields:
- beginning, the is end The
The rest of the cycle looks like this:
- (beginning, the is end The), (the) >===> the beginning, the is end The
- (the beginning, the is end The) (beginning) >===> beginning the beginning, the is end The
- (beginning the beginning, the is end The) (the) >===> the beginning the beginning, the is end The
- (the beginning the beginning, the is end The) (end) >===> end the beginning the beginning, the is end The
I find this an immensely satisfying process to contemplate simply because it so very logically runs counter to my intuitions. I keep expecting it to do something different, but when I think it through I see exactly why it does what it does. How many real world uses for this I will discover I don't know, but I will treasure each one as I encounter it.
Listing 1 shows the complete code for this simple program. In this version of the ReverseSentence method, you see how to convert the sentence int List<string> rather than an array of string. I use the ToList() LINQ operator to perform this conversion, so you are seeing a sneak peak of an operator I haven't yet covered in this series.
Listing 01: This code shows how to use the Aggregate() and ToList() operators that are declared in the Enumerator class and which are part of LINQ to Objects.
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqFarmSeed02
{
class Program
{
private static string ReverseString(string sentence)
{
List<string> words = new List<string>(sentence.Split(' ').ToList());
return words.Aggregate((a, b) => b + " " + a);
}
static void Main(string[] args)
{
string sentence = "The end is the beginning, the beginning the end";
Console.WriteLine(sentence);
string result = ReverseString(sentence);
Console.WriteLine(result);
}
}
}
In this post you have seen how to use the Aggregate operator to reverse the order of a list of words. Thinking through the way this operator works on a list of strings can help you understand exactly how it is implemented and exactly what it does.
-----------------
Download the source code from the LINQ Farm.
I want to get my hands dirty; show me more LINQ Farm posts.
Comments
Anonymous
February 06, 2008
You've been kicked (a good thing) - Trackback from DotNetKicks.comAnonymous
February 06, 2008
What's the point of your .ToList() call? I could understand this: List<string> words = sentence.Split(' ').ToList(); And I could understand this: List<string> words = new List<string>(sentence.Split(' ')); but your use of the .ToList() extension method is equivalent to: List<string> words = new List<string>(new List<string>(sentence.Split(' '))); which is just...insane, frankly.Anonymous
February 06, 2008
Charlie Calvert's LINQ Farm SeedsAnonymous
February 06, 2008
thanks for the seeds :D YOU ARE GREAT!!!!!Anonymous
February 07, 2008
Sharepoint Two New Tools for SharePoint Development [Via: axshon ] WPF Visio 2007 to XAML Export Add-in...Anonymous
February 07, 2008
Link Listing - February 6, 2008Anonymous
February 08, 2008
s.Split(' ').Aggregate("", (a, b) => (b + " " + a), c => c) is simplerAnonymous
February 10, 2008
Charlie Calvert is a C# Community Evanelist at Microsoft and his blog is filled with informative postsAnonymous
February 14, 2008
While this works, it is somewhat counter intuitive, so I think you would be better off using Enumberable.Reverse (and removing the unnecessary temporary lists -- array from String.Split is IEnumberable<string>): private static string ReverseString(string sentence) { return sentence.Split(' ').Reverse().Aggregate((a,b) => a+" "+b); }Anonymous
February 14, 2008
Why cal ToList on the string[] returned from split? arrays support IEnumerable and we should be able to call agregate on the string[] directly>].Anonymous
August 03, 2008
Lexapro. Generic lexapro. Lexapro and pin and needles. What is lexapro.