I love lambda expressions (part 1)!

In the beginning, you are nervous, not sure and even afraid. Slowly you get used to it by experimenting and finally you can’t live without it anymore. To avoid confusion, I’m talking about lamda expressions here.  To prove my point, let’s first go back into time.

If we would need to filter out a list of numbers to get all the numbers smaller than 25, following code does that fine:

List<int> numbers = new List<int> { 1, 7, 16, 23, 41, 66 };
List<int> numbersSmallerThan25 = new List<int>();
foreach (int number in numbers)
{ if (number < 25) { numbersSmallerThan25.Add(number); } }

Using predicate delegates

Of course, we can do a lot better, by creating a method that checks if a passed number is smaller than 25, and passing this method as a parameter to the FindAll method of the list:

static void Main(string[] args)
{
List<int> numbers = new List<int> { 1, 7, 16, 23, 41, 66 };
List<int> numbersSmallerThan25 =
numbers.FindAll(MatchNumberSmallerThan25);
}
private static bool MatchNumberSmallerThan25(int number)
{
return number < 25;
}

Here we make use of predicate delegates. A predicate delegate is a method that returns true or false. In this case we define a MatchNumberSmallerThan25 method, which returns true if the passed number is smaller than 25. Now we can pass this predicate to the FindAll method of the generic list. As a result, the FindAll method executes the MatchNumberSmallerThan25  method for each item in the generic list. For each call that returns true, the collection item is added to the returning collection of the FindAll method.

Using anonymous methods

This already seems a lot better, however, we still have to create private methods for every case we have, methods that we probably never reuse. So we could improve this by using anonymous methods:

List<int> numbers = new List<int> { 1, 7, 16, 23, 41, 66 };
List<int> numbersSmallerThan25 = numbers.FindAll(
delegate(int number) { return number < 25; } );

In this example we are passing an anonymous inline piece of code as a predicate delegate to the FindAll method, which does exactly the same as the MatchNumberSmallerThan25 method. This offers us a number of advantages: no need to clutter your code with private named methods, the code is where it is used, no need to specify the return type (it is inferred from the signature of the delegate type to which the anonymous method is being cast to) and you can refer to the outer variables from within the anonymous method.

Using lambda expressions

As the title of this blog suggests, we still have a way to improve the code above. So let’s dot that:

static void Main(string[] args)
{
List<int> numbers = new List<int> { 1, 7, 16, 23, 41, 66 };
List<int> numbersSmallerThan25 = numbers.FindAll(n => n < 25);
}

Did you notice the amount of code we have left? And this is all thanks to the beloved lambda expressions! At first it seems a bit cryptic, so what is a lambda expression? It’s nothing more than an anonymous method used to create a delegate, and that takes takes the form:

argument-list => expression

In our example, the lambda expression consists of an argument named ‘n’ (which is implicitely typed as an integer), then the lambda operator ‘=>’, followed by an expression ‘n < 25’.

You could read it as: ‘There’s a method that takes one parameter n and a list of integers; and it returns every number from that list that is smaller than 25 ‘. This lambda expression is then passed to the FindAll method of the generic collection. Actually, this lambda expression is a very small, compact, anonymous method that is another way of writing an anonymous method, which is also more readable and verbose.

A closer look

If we look at the FindAll signature, we see that it expects a parameter of type Predicate<T>, and because we are applying it to a list of integers, it has to be of type Predicate<int>. So we could explicitely create and use such predicate as follows:

List<int> numbers = new List<int> { 1, 7, 16, 23, 41, 66 };
Predicate<int> predNumbersSmallerThan25 = n => n < 25;
List<int> numbersSmallerThan25 = numbers.FindAll(predNumbersSmallerThan25);

However, FindAll is a .NET 2.0 method, and the preferred way is using the .NET 3.5 Where method, which expects a Func<T1, TResult> parameter. T1 is the type of the parameter (which is int) and TResult is the type of the returned value (which is bool). So we end up with the following code, which has exact the same results as the previous code:

List<int> numbers = new List<int> { 1, 7, 16, 23, 41, 66 };
Func<int, bool> funcNumbersSmallerThan25 = n => n < 25;
List<int> numbersSmallerThan25 =
numbers.Where(funcNumbersSmallerThan25).ToList();

Other examples

Now that you have fallen in love with lambda expressions too, some other examples:

// Add 5 to every number in the collection
List<int> numbersAdded5 = numbers.ConvertAll(n => n + 5);
// Sort list descending (lambda expression with two arguments!)
numbers.Sort( (a,b) => b-a );
// Groups collection of numbers into two groups containing
// odd or even numbers
var grouped = numbers.GroupBy(n => n%2==0);

Note the ‘var’ keyword in the last example. It means that the compiler will infer the type for you, it does not mean that it’s some kind of variant data type that can change. In this case, the grouped variable will always be of type ‘System.Linq.GroupedEnumerable<int,bool,int>’, because that is the return type of the GroupBy method.

There’s more to learn about lambda expressions… in the second part!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s