Exploring Lambda Expressions in C#

Exploring Lambda Expressions in C#

Excerpt from my (upcoming) book: The Other Topics.

Introduction

Lambda expressions are powerful and concise features introduced in C# that allow developers to write compact and expressive code. They provide a convenient way to define inline functions or delegates, making code more readable and efficient. This article will delve into the concept of lambda expressions, their syntax, and practical use cases in C#.

What is Lambda Expression?

A Lambda Expression is a simple function in a single line. "A mathematical phrase that groups numbers, variables, and operators to show the value of something." It's essentially an unnamed method that provides a concise and functional syntax and is usually used to write anonymous methods.

It can be used to generate delegates or expression tree types based on the functional programming concept and is an anonymous function that can be used to create delegates or expression trees. It provides a concise way to define functionality without explicitly declaring a separate method. Lambda expressions are often used in scenarios where a small piece of code needs to be passed as an argument to a method or used in LINQ queries.

Lambda Expressions Syntax

The basic syntax of a lambda expression in C# is:

(parameters) => expression

The parameters are enclosed in parentheses and separated by commas, just like in a regular method definition. The => arrow separates the parameter list from the expression that makes up the lambda expression's body.

Example: Adding Two Numbers

Here is an example of a lambda expression that adds two numbers:

(int x, int y) => x + y

The above lambda expression takes two integer parameters, x and y, and returns their sum. Note that the data types of the parameters are explicitly specified.

Lambda Expressions in Action: Code Examples

Now let's put it in perspective. If we have a class ManipNumbers and a list of random positive numbers, and we want to derive only a set of numbers from our existing list that holds a wider range, our code, without Lambda Expressions, may look something like this:

class ManipNumbers
{
    static void main (string[] args)
    {  
        //list with random numbers
        var randomNumbers = new List<int> {13, 24, 4, 2, 7, 8, 0, 1, 37, 3};

        //create the Lists we'll be needing
        var evenNumbers = new List<int> ();
        var oddNumbers = new List<int> ();
        var numbersAbove7 = new List<int> ();

        //we're going to add even and odd numbers to their resp. Lists
        foreach(var number in randomNumbers)
        {
            if(number % 2 == 0)
            {
                evenNumbers.Add(number); // → 24, 4, 2, 8
            }
            else // if(number % 2 != 0)
            {
                oddNumber.Add(number); // → 13, 7, 1, 37, 3
            }
         }
    }
}

But with Lambda Expressions, our code can be shortened to something like this:

class ManipNumbers
{
   static void main (string[] args)
   {
     //list with random numbers
     var randomNumbers = new List<int> {13, 24, 4, 2, 7, 8, 0, 0, 1, 37, 3};

     //create the Lists, get the numbers, and add them to their resp. Lists
     var oddNumbers = randomNumbers.Where(n => n % 2 != 0); // → 13, 7, 1, 37, 3
     var evenNumbers = randomNumbers.Where(n => n % 2 == 0); // → 24, 4, 8, 2
     var numbersAbove7 = randomNumbers.Where(n => n > 7); // → 13, 24, 8, 37
   }
}

We began by creating a new variable named oddNumbers to store our odd numbers after we derived them, then we referred to our randomNumbers List and used the inbuilt method Where() which filters a sequence of values based on a predicate, providing our Lambda Expression as its parameter. The Lambda Expression explains the kind of number it's looking for—specifically, one that, when divided by two (using the modulo operator) will always have a remainder. Then we do the same for the evenNumbers and numbersAbove7, only changing our rules for deriving numbers, using the Lambda Expression.

Case Study: Jon Bellion's Songs

Now, let's look at another example.

Imagine you work as a C# developer for my favorite music company, Spotify, and each day, Spotify wants to display on the app home screen some of Jon Bellion's songs for their users who listen to him, like me, but only the ones with a global rating of 8.5 and above. And you're tasked with coding the method responsible for selecting the songs.

Given the List:

var JonBellionSongslist = new List<Song>
{
 //the release dates were gotten from Google searches, but the ratings are not accurate, except I'm a super lucky guesser
 new Song{name = "Ooh", releaseDate = new DateTime (2014, 09, 23), rating = 9.0f },

 new Game{name = "Human", releaseDate = new DateTime(2016, 03, 4), rating = 8.5f },

 new Song{name = "Stupid Deep", releaseDate = new DateTime(2018, 11, 9), rating = 8.0f},

 new Song{name = "Blu", releaseDate = new DateTime(2018, 11, 9), rating = 8.0},

 new Song{name = "Guillotine", releaseDate= new DateTime(2016, 04, 23), rating = 9},

 new Song{name = "Kingdom Come", releaseDate = new DateTime(2013, 12, 10), rating = 8.0},

 new Song{name = "All Time Low", releaseDate = new DateTime(2016, 5,13), rating = 8.0},

 new Song{name = "Maybe IDK", releaseDate = new DateTime(2016, 6, 3), rating = 7.5}
};

Without Lambda Expressions, your song-fetching method might look like this:

//method to select the songs
static Song[] JonSongsOver85(IEnumerable<Song>
{
 var JonSongs = new List<Song>();

 foreach(var song in songs)
 {
   if(song.rating >= 8.5)
   {
     JonSongs.Add(song);
   }
 }

 return JonSongs.ToArray();
}

But with Lambda Expressions, we can make this method look shorter and cleaner like so:

//the method that selects the songs
static Song[] JonSongsOver85(IEnumerable<Song> songs)
{
 IEnumerable<Song> JonSongs = songs.Where(sn => sn.rating >= 8.5);
 return JonSongs.ToArray();
}

Conclusion

In summary, although Lambda Expressions do the same thing traditional methods do under the hood, they facilitate the creation of faster, more concise, and reusable code.

Remember to use lambda expressions judiciously, keeping code readability and maintainability in mind. With practice, you can harness the power of Lambda Expressions to write elegant and efficient code in your C# applications.

This is an excerpt from my upcoming book, The Other Topics. A guide through several topics in C#, including Events, Delegates, Generics, etcetera, with some projects that utilize these concepts to seal things up.