I originally published this post on my blog a couple of weeks ago. It's part of a post series about LINQ.
Let's take a deeper look at one of the most common LINQ methods: GroupBy
.
The GroupBy method groups the elements of a collection based on a grouping key. This method returns a collection of "groups" or "buckets" organized by that key.
The GroupBy
method receives as a parameter a delegate with the property to use as a key when grouping elements.
For example, let's group our catalog of movies by rating.
var movies = new List<Movie>
{
new Movie("Titanic", 1998, 4.5f),
new Movie("The Fifth Element", 1997, 4.6f),
new Movie("Terminator 2", 1991, 4.7f),
new Movie("Avatar", 2009, 5),
new Movie("Platoon", 1986, 4),
new Movie("My Neighbor Totoro", 1988, 5)
};
// Group our catalog of movies based on their rating
var groupedByRating = movies.GroupBy(movie => movie.Rating);
// 👆👆👆
foreach (var group in groupedByRating)
{
// Each group or bucket has a Key property
Console.WriteLine($"Rating: {group.Key}");
foreach (var movie in group)
{
Console.WriteLine($"{movie.Name}");
}
Console.WriteLine();
}
// Output:
//Rating: 4.5
//Titanic
//
//Rating: 4.6
//The Fifth Element
//
//Rating: 4.7
//Terminator 2
//
//Rating: 5
//Avatar
//My Neighbor Totoro
//
//Rating: 4
//Platoon
record Movie(string Name, int ReleaseYear, float Rating);
We used Top-level statements, records and implicit usings statements. All boilerplate code is gone!
Also, to group our catalog of movies, we used movie => movie.Rating
as the parameter for the GroupBy
method.
How to transform every group
Apart from grouping collections by a key, the GroupBy
method has another overload to transform each group or bucket of items.
Let's change the previous example to count the movies with the same rating.
var movies = new List<Movie>
{
new Movie("Titanic", 1998, 4.5f),
new Movie("The Fifth Element", 1997, 4.6f),
new Movie("Terminator 2", 1991, 4.7f),
new Movie("Avatar", 2009, 5),
new Movie("Platoon", 1986, 4),
new Movie("My Neighbor Totoro", 1988, 5)
};
// Transform every group into a RatingCount type
var countByRating = movies.GroupBy(movie => movie.Rating,
(rating, movies) => new RatingCount(rating, movies.Count());
// 👆👆👆
foreach (var group in countByRating)
{
Console.WriteLine($"{group.Rating}: [{group.Count}]");
}
// Output:
//4.5: [1]
//4.6: [1]
//4.7: [1]
//5: [2]
//4: [1]
record Movie(string Name, int ReleaseYear, float Rating);
record RatingCount(float Rating, int Count);
This time, we passed a second parameter to the GroupBy
method.
The first parameter was still the grouping key, as usual. But, the second one was a delegate that received the grouping key and the elements of each group. We named the two parameters: rating
and movies
.
With the ratings and the movies per rating, we transformed every group of movies into a new object, RatingCount
.
Since we wanted to count the movies with the same rating, we used another LINQ method: Count
.
How to group by more than one property
We've used Rating
as the grouping key. But we can group the elements of a collection by more than one grouping property.
With the GroupBy method, to group a collection by more than one property, use a custom object as the grouping key.
For example, to group our catalog of movies by release year and reating, we can write a LINQ query like this,
var groupByReleasedYearAndRating = movies.GroupBy(movie => new
{
movie.ReleaseYear,
movie.Rating
});
Then, the Key
property would be an object, instead of a primitive value. It means, we can access both the ReleaseYear
and the Rating
of each group.
For example,
var groupByReleasedYearAndRating = movies.GroupBy(movie => new { movie.ReleaseYear, movie.Rating });
foreach (var group in groupByReleasedYearAndRating)
{
var groupingKey = group.Key;
var releaseYear = groupingKey.ReleaseYear;
// 👆👆👆
var rating = groupingKey.Rating;
// 👆👆👆
// Do something with the releaseYear and rating...🤖
foreach (var movie in group)
{
// Do something with each movie in the group...🤖
}
}
Voilà ! That's the GroupBy method. It creates groups or buckets with the elements of a collection and transforms each group.
If you noticed the output of our previous examples, the GroupBy
method grouped the elements without sorting them. For that, we would need the OrderBy
method.
Want to write more expressive code for collections? Join my Udemy course, Getting Started with LINQ, and master everything you need to work productively with LINQ — all in less than two hours!
Happy coding!
Top comments (0)