GroupBy is a LINQ functionality which allows to group items from a collection based on a given key. It’s an equivalent to SQL’s GROUP BY clause. In this article we’ll show various examples of usage, starting from the simplest grouping by one key, through grouping by multiple keys, custom result selector and all of that in two variants: Lambda and Query expression.
Let’s prepare sample data which we could operate on to present various examples of group by. For this purpose we define Person class and create 10 objects collected within a list.
|
public class Person
{
public string Forename { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var people = new List<Person>()
{
new Person() { Forename = “John”, Surname = “Smith”, Age = 33 },
new Person() { Forename = “Michael”, Surname = “Jones”, Age = 41 },
new Person() { Forename = “Susan”, Surname = “Taylor”, Age = 21 },
new Person() { Forename = “Michael”, Surname = “Evans”, Age = 41 },
new Person() { Forename = “James”, Surname = “Wilson”, Age = 39 },
new Person() { Forename = “Michael”, Surname = “Johnson”, Age = 35 },
new Person() { Forename = “Susan”, Surname = “Davies”, Age = 21 },
new Person() { Forename = “Susan”, Surname = “Robinson”, Age = 47 },
new Person() { Forename = “John”, Surname = “Wright”, Age = 44 },
new Person() { Forename = “Susan”, Surname = “Walker”, Age = 21 }
};
|
Single key selector
First scenario is to group people collection by forename.
Lambda expression
|
var groups = people.GroupBy(x => x.Forename);
|
Query expression
|
var groups = from p in people
group p by p.Forename;
|
Both Lambda and Query expression generates the same results which can be displayed with foreach loops. We need to use two of them as first level is collection of groups and each group contains collection of people within particular group.
|
foreach (var group in groups)
{
Console.WriteLine($“Group key: {group.Key}”);
foreach (var person in group)
{
Console.WriteLine($“Forename: {person.Forename}, Surname: {person.Surname}, Age: {person.Age}”);
}
Console.WriteLine();
}
|
In the results we can see four groups, where people within each group share the same forename.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Group key: John
Forename: John, Surname: Smith, Age: 33
Forename: John, Surname: Wright, Age: 44
Group key: Michael
Forename: Michael, Surname: Jones, Age: 41
Forename: Michael, Surname: Evans, Age: 41
Forename: Michael, Surname: Johnson, Age: 35
Group key: Susan
Forename: Susan, Surname: Taylor, Age: 21
Forename: Susan, Surname: Davies, Age: 21
Forename: Susan, Surname: Robinson, Age: 47
Forename: Susan, Surname: Walker, Age: 21
Group key: James
Forename: James, Surname: Wilson, Age: 39
|
Multiple key selector
Above example was the simplest but it is also possible to group by multiple keys. To present it let’s group our people collection by both forename and age.
Lamda expression
|
var groups = people.GroupBy(x => (x.Forename, x.Age));
|
Query expression
|
var groups = from p in people
group p by (p.Forename, p.Age);
|
Results can be printed using the code from previous example. This time we’ve got seven groups of people, where each group contains only people with the same forename and age.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Group key: (John, 33)
Forename: John, Surname: Smith, Age: 33
Group key: (Michael, 41)
Forename: Michael, Surname: Jones, Age: 41
Forename: Michael, Surname: Evans, Age: 41
Group key: (Susan, 21)
Forename: Susan, Surname: Taylor, Age: 21
Forename: Susan, Surname: Davies, Age: 21
Forename: Susan, Surname: Walker, Age: 21
Group key: (James, 39)
Forename: James, Surname: Wilson, Age: 39
Group key: (Michael, 35)
Forename: Michael, Surname: Johnson, Age: 35
Group key: (Susan, 47)
Forename: Susan, Surname: Robinson, Age: 47
Group key: (John, 44)
Forename: John, Surname: Wright, Age: 44
|
Custom result selector
Last example I’d like to present here is combining group by with custom result selector. In this scenario each group in the returned collection has GroupName property containing a key name, GroupSize property containing number of items in a group, and GroupItems containing list of people in a group.
Lambda expression
|
var groups = people.GroupBy(x => (x.Forename)).Select(x => new
{
GroupName = x.Key,
GroupSize = x.Count(),
GroupItems = x.ToList()
});
|
Query expression
|
var groups = from p in people
group p by p.Forename
into g
select new
{
GroupName = g.Key,
GroupSize = g.Count(),
GroupItems = g.ToList()
};
|
Code to display results needs to be slightly modified to reflect above selector changes.
|
foreach (var group in groups)
{
Console.WriteLine($“Group name: {group.GroupName}”);
Console.WriteLine($“Group size: {group.GroupSize}”);
foreach (var person in group.GroupItems)
{
Console.WriteLine($“Forename: {person.Forename}, Surname: {person.Surname}, Age: {person.Age}”);
}
Console.WriteLine();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
Group name: John
Group size: 2
Forename: John, Surname: Smith, Age: 33
Forename: John, Surname: Wright, Age: 44
Group name: Michael
Group size: 3
Forename: Michael, Surname: Jones, Age: 41
Forename: Michael, Surname: Evans, Age: 41
Forename: Michael, Surname: Johnson, Age: 35
Group name: Susan
Group size: 4
Forename: Susan, Surname: Taylor, Age: 21
Forename: Susan, Surname: Davies, Age: 21
Forename: Susan, Surname: Robinson, Age: 47
Forename: Susan, Surname: Walker, Age: 21
Group name: James
Group size: 1
Forename: James, Surname: Wilson, Age: 39
|
Need Help with Your C# Projects?
We offer expert support and development services for projects of any size. Contact us for a free consultation and see how we can help you succeed.
CONTACT US NOW