Complete guide to C# LINQ and lambda expressions

Let’s get acquainted with C# LINQ and lambda expressions. We will start by learning about lambda expressions and see how to use the most common ones. Afterward, we will learn how to use C# LINQ, what LINQ queries look like, and see the most used queries in action.

In this comprehensive guide to C# LINQ and lambda expressions, we will dive deep into their functionalities and explore their practical applications. By understanding the fundamentals of lambda expressions and mastering LINQ queries, you’ll gain the tools to write efficient and concise code in C#.

What are lambda expressions?

Lambda expressions are anonymous functions that contain expressions or sequences of operators. A lambda expression takes one or more parameters and returns a value. C# lambda expressions use the “goes to” operator (=>). On the left side of the C# lambda expression operator, we find the input parameters. On the right side, we have the expression or code block that works with the input parameters. This is how a lambda expression looks like

listOfObjects.FindAll(parameter=> expression);

Filtering collections using C# lambda expression

One of the most used extension methods is the FindAll method. With this method, we can filter objects in a list based on some conditions. Assuming we have a list of animals, this is how we would use C# lambda expression to filter the animals starting with the letter B.

var listOfAnimals = new List<string> {
    "Awl", "Bear", "Beaver", "Snake"
};
var listOfAnymalsStartingWithLetterB = listOfAnimals.FindAll(a => a.StartsWith("B"));
foreach (var animal in listOfAnymalsStartingWithLetterB)
{
    Console.WriteLine(animal);
}

Select fields using C# lambda expression

In this example, we have a list of objects having multiple properties. We want to get a list of one property of the object, in our case we want the list of animal names.

var listOfAnimals = new List<Animal>() {
    new Animal {
        Name = "Bear",
        Age = 2
    },
    new Animal {
        Name = "Awl",
        Age = 1
    },
    new Animal {
        Name = "Snake",
        Age = 3
    },
    new Animal {
        Name = "Beaver",
        Age = 1
    }
};
var animalNames = listOfAnimals.Select(a => a.Name);
foreach (var name in animalNames)
{
    Console.WriteLine(name);
}

When we execute the code from above we will see this:

Bear
Awl
Snake
Beaver

Sorting using C# lambda expression

At one point or another, you will find yourself in the need of sorting a list. For this, we have OrderBy and OrderByDescending. Let’s sort the list of animals from our previous example.

var animalsSortedByNameAscending = listOfAnimals.OrderBy(a => a.Name);
foreach (var animal in animalsSortedByNameAscending)
{
    Console.WriteLine(animal.Name);
}
var animalsSortedByNameDescending = listOfAnimals.OrderByDescending(a => a.Name);
foreach (var animal in animalsSortedByNameDescending)
{
    Console.WriteLine(animal.Name);
}

C# LINQ

LINQ is a short name for Language-Integrated Query. It is a set of extensions of .NET, that includes language-integrated queries and operations of a certain data source. The way LINQ is working with collections is similar to most SQL languages. You will find similar keywords in LINQ that are the same with SQL: select, from, where, etc. This is what a LINQ query looks like:

from item
in list

This C# LINQ query would read something like this: for each element of the “list” assign a variable “item” and use it to reference items further in the query.

Filtering collections using C# LINQ

We will now filter the list of animals and search for animal names starting with the letter B. This is the same example we used in the filtering collections using C# lambda expression.

var listOfAnimals = new List<string> {
    "Awl", "Bear", "Beaver", "Snake"
};
var listOfAnymalsStartingWithLetterB = 
from animal in listOfAnimals 
where animal.StartsWith("B") 
select animal;
foreach (var animal in listOfAnymalsStartingWithLetterB)
{
    Console.WriteLine(animal);
}

Sorting using C# LINQ

Once again we will translate the sorting using C# lambda expression to C# LINQ and see what we get.

var animalsSortedByNameAscending = 
from animal in listOfAnimals
orderby animal.Name
select animal;
foreach (var animal in animalsSortedByNameAscending)
{
    Console.WriteLine(animal.Name);
}
var animalsSortedByNameDescending = 
from animal in listOfAnimals
orderby animal.Name descending
select animal;
foreach (var animal in animalsSortedByNameDescending)
{
    Console.WriteLine(animal.Name);
}

Grouping with C# LINQ

In some cases, we might need to group items in a list and create a new list with them. Let’s assume we need a list of animals grouped by the first letter in the name. Our program should show us the total number of animals starting with a specific letter.

var listOfAnimals = new List<string> {
    "Awl", "Bear", "Beaver", "Snake"
};
var groupedAnimals =
from animal in listOfAnimals
group animal by animal[0] into groupedAnimal
select new { FirstLetter = groupedAnimal.Key, AnimalCount = groupedAnimal.Count() };
foreach (var group in groupedAnimals)
{
    Console.WriteLine($"We found {group.AnimalCount} animal names starting with the letter {group.FirstLetter}");
}

The same example of grouping with C# LINQ can be translated to lambda expression.

var listOfAnimals = new List<string> {
    "Awl", "Bear", "Beaver", "Snake"
};
var groupedAnimals = listOfAnimals
.GroupBy(a => a[0])
.Select(groupedAnimal => new { FirstLetter = groupedAnimal.Key, AnimalCount = groupedAnimal.Count() });
foreach (var group in groupedAnimals)
{
    Console.WriteLine($"We found {group.AnimalCount} animal names starting with the letter {group.FirstLetter}");
}

Joining with C# LINQ

Similar to what we can achieve with a join statement in SQL, we can achieve with C# LINQ. Joining with LINQ is a bit more complicated than the other statements. A join statement in LINQ looks something like this:

from collection1VariableName in collection1 join
collection2VariableName in collection2 on
collection1CompareCondition equals collection2CompareCondition

Looks a bit harder to read and understand, altho it has some similarities to SQL query. It might be easier to understand with an example. Assuming we have a list of animals and a list of animal categories, here is how we would extract a list of animals with animal categories.

var animals = new List<Animal>() {
    new Animal {
        Name = "Bear",
        Age = 2,
        CategoryId = 1
    },
    new Animal {
        Name = "Awl",
        Age = 1,
        CategoryId = 1
    },
    new Animal {
        Name = "Chicken",
        Age = 3,
        CategoryId = 2
    }
};
var categories = new List<AnimalCategory>(){
    new AnimalCategory{
        CategoryId = 1,
        Name = "Wild"
    },
    new AnimalCategory{
        CategoryId = 2,
        Name = "Domestic"
    }
};
var animalsWithCategoryName =
from animal in animals
join category in categories
on animal.CategoryId equals category.CategoryId
select new { Name = animal.Name, Category = category.Name };
foreach (var animal in animalsWithCategoryName)
{
    Console.WriteLine(animal);
}

Console:

{ Name = Bear, Category = Wild }
{ Name = Awl, Category = Wild }
{ Name = Chicken, Category = Domestic }

Another great feature of C# LINQ is the fact that it supports nested queries. The example from above can be written using nested queries as well.

var animalsWithCategoryName =
from animal in animals
select new
{
    Name = animal.Name,
    Category =
(from category in categories
 where category.CategoryId == animal.CategoryId
 select category.Name).First()
};

If you run the code you will notice the result is the same.

Conclusions

Please bear in mind that what we can achieve with lambda expressions and LINQ queries can be done with simple loops. You should also remember that lambda expressions and LINQ queries are slower than using loops. Beware when and how you use these two.

We had a look over C# lambda expressions and C# LINQ queries. Learned how to use basic methods like filtering, sorting, and grouping. I hope you found this article useful. If you have any questions please use the comments section below.