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.