GroupBy Linq Example

Grouping lists of data can be useful. In the example below I will outline basic grouping and how to group on multiple fields.

A basic example

In this example, we have an array of people. Let's say we want to group these by Gender since this is common in each object. The result we are aiming for will be a list of genders. Then, within each gender group, we should have the people that fall under that gender. So, the resulting output should be 2 Genders, male and female. Within the male group, we should have Vernon and Thomas and in the female group, we should have Carrie. There are a few ways we can do this, so let's take a look at each one, and you can decide which you like or makes more sense to you.

Method syntax 1

This method uses the .GroupBy method syntax and the lambda expression used specifies the Gender, like so: p => p.Gender. This is then chained to the Select method which produces a new anonymous object with the Gender and a list of people with the corresponding gender. The select method here is entirely optional and you can just have the .GroupBy method.

Live example: https://dotnetfiddle.net/MfuQxr

var people = new[]
    {
        new
            {
                Name = "Vernon",
                Gender = "Male",
            },
        new
            {
                Name = "Carrie",
                Gender = "Female"
            },
        new
            {
                Name = "Thomas",
                Gender = "Male"
            }
    };

//Method 1:
var peopleByGender = people.GroupBy(p => p.Gender)
                            .Select(x => new { Gender = x.Key, People = x }); 
// output:
// Male
//  Vernon
//  Thomas
// Female
//  Carrie

Method syntax 2

This is a little more complex but results in the same output as the first. It combines the GroupBy and Select all in one method operation, which is convenient but may not be as readable at first. The first part of the lambda expression is the particular key to group by, which is Gender - same as Method 1. The next argument takes a Func which is essentially the selector. In other words, it's the .Select method statement in the first example.

Live example: https://dotnetfiddle.net/GYaf0z

var people = new[]
    {
        new
            {
                Name = "Vernon",
                Gender = "Male",
            },
        new
            {
                Name = "Carrie",
                Gender = "Female"
            },
        new
            {
                Name = "Thomas",
                Gender = "Male"
            }
    };

//Method 2:
var peopleByGender = people.GroupBy(arg => arg.Gender, 
                                   (key, list) => new {Gender = key, People = list});

// output:
// Male
//  Vernon
//  Thomas
// Female
//  Carrie

Query syntax

Another way of grouping is, of course, using the Query syntax, which is my personal preference. It uses the following syntax to perform the group by: group [x] by [y] into [z]. Here, [x] is the particular object to be grouped, [y] is the key or property to group by and the into [z] is an alias of where the grouping result should reside in. So, the full statement is group person by person.Gender into g.

Live example: https://dotnetfiddle.net/WQO378

var people = new[]
    {
        new
            {
                Name = "Vernon",
                Gender = "Male",
            },
        new
            {
                Name = "Carrie",
                Gender = "Female"
            },
        new
            {
                Name = "Thomas",
                Gender = "Male"
            }
    };

//Method 3:
var peopleByGender = from person in people
                     group person by person.Gender
                     into g
                     select new {Gender = g.Key, People = g};

// output:
// Male
//  Vernon
//  Thomas
// Female
//  Carrie

GroupBy - Multiple

In some cases, you may want to group by multiple properties or keys. In this example, we will group by Gender and City.

Method syntax

Similar to the basic groupby example above, we can specify multiple properties using an anonymous object. Here we are using new { arg.Gender, arg.City }.

Live example: https://dotnetfiddle.net/4bMd42

var people = new[]
    {
        new
            {
                Name = "Vernon",
                Gender = "Male",
                City = "London",

            },
        new
            {
                Name = "Carrie",
                Gender = "Female",
                City = "London"
            },
            new
            {
                Name = "Joanna",
                Gender = "Female",
                City = "London"
            },
        new
            {
                Name = "Thomas",
                Gender = "Male",
                City = "Paris"
            }
    };

var peopleByGender = people.GroupBy(arg => new { arg.Gender, arg.City })
                           .Select(grouping => new
                           {
                              Gender = grouping.Key.Gender,
                              City = grouping.Key.City,
                              People = grouping
                           });

// output:
// Male London
//  Male London Vernon
// Female London
//  Female London Carrie
//  Female London Joanna
// Male Paris
//  Male Paris Thomas

Query syntax

As with the method syntax, we too can use a similar anonymous object, new { p.Gender, p.City }.

Live example: https://dotnetfiddle.net/hIRlAv

var people = new[]
    {
        new
            {
                Name = "Vernon",
                Gender = "Male",
                City = "London",

            },
        new
            {
                Name = "Carrie",
                Gender = "Female",
                City = "London"
            },
            new
            {
                Name = "Joanna",
                Gender = "Female",
                City = "London"
            },
        new
            {
                Name = "Thomas",
                Gender = "Male",
                City = "Paris"
            }
    };

var peopleByGender = from p in people
                     group p by new { p.Gender, p.City } // this is how to group by multiple properties
                     into g
                     select new
                     {
                        City = g.Key.City,
                        Gender = g.Key.Gender,
                        People = g
                     };

// output:
// Male London
//  Male London Vernon
// Female London
//  Female London Carrie
//  Female London Joanna
// Male Paris
//  Male Paris Thomas

GroupBy - Batching

This particular grouping can be useful at times. If you have a large list and would like to break them up into groups of say 5, this particular method of grouping is pretty neat.

This can be useful in various scenarios. They can range from UI purposes to server-side improvements.

So, the example below,

Method syntax

Here we have a list of 12 currencies with exchange rates. We are going to break this list into groups of 5. The end result would be 2 batches of 5 and 1 batch of 2.

Live example: https://dotnetfiddle.net/jUxGcZ

var exchangeRates = new[]
                    {
                        new {Currency = "USD", Rate = 1.2701},
                        new {Currency = "JPY", Rate = 138.97},
                        new {Currency = "BGN", Rate = 1.9558},
                        new {Currency = "CZK", Rate = 27.54},
                        new {Currency = "DKK", Rate = 7.4432},
                        new {Currency = "GBP", Rate = 0.7827},
                        new {Currency = "HUF", Rate = 312.18},
                        new {Currency = "LTL", Rate = 3.4528},
                        new {Currency = "PLN", Rate = 4.1827},
                        new {Currency = "RON", Rate = 4.4125},
                        new {Currency = "SEK", Rate = 9.2018},
                        new {Currency = "CHF", Rate = 1.2071},
                    };

var batchNumber = 5;    // the batch size
var batches = exchangeRates.Select((exchangeRate, index) =>
                            new {ExchangeRate = exchangeRate, Index = index})
                           .GroupBy(x => x.Index/batchNumber);

// output:
// ------------
// Batch no: 1
// ------------
// 1 : USD 1.2701
// 2 : JPY 138.97
// 3 : BGN 1.9558
// 4 : CZK 27.54
// 5 : DKK 7.4432
// ------------
// Batch no: 2
// ------------
// 1 : GBP 0.7827
// 2 : HUF 312.18
// 3 : LTL 3.4528
// 4 : PLN 4.1827
// 5 : RON 4.4125
// ------------
// Batch no: 3
// ------------
// 1 : SEK 9.2018
// 2 : CHF 1.2071

Query syntax

I'll admit, I'm cheating a little here with the query syntax. I'm using the .Select method with an index and combining it with the query syntax. But I hope to get the message across. Live example: https://dotnetfiddle.net/Mxk1LB

var exchangeRates = new[]
                    {
                        new {Currency = "USD", Rate = 1.2701},
                        new {Currency = "JPY", Rate = 138.97},
                        new {Currency = "BGN", Rate = 1.9558},
                        new {Currency = "CZK", Rate = 27.54},
                        new {Currency = "DKK", Rate = 7.4432},
                        new {Currency = "GBP", Rate = 0.7827},
                        new {Currency = "HUF", Rate = 312.18},
                        new {Currency = "LTL", Rate = 3.4528},
                        new {Currency = "PLN", Rate = 4.1827},
                        new {Currency = "RON", Rate = 4.4125},
                        new {Currency = "SEK", Rate = 9.2018},
                        new {Currency = "CHF", Rate = 1.2071},
                    };

var batchNumber = 5;    // the batch size

var batches2 = from e in exchangeRates.Select((exchangeRate, index) =>
                                       new {ExchangeRate = exchangeRate, Index = index})
                                       group new {e.ExchangeRate, e.Index}
                                       by e.Index/batchNumber
                                       into groupedBatches
                                       select groupedBatches;

// output:
// ------------
// Batch no: 1
// ------------
// 1 : USD 1.2701
// 2 : JPY 138.97
// 3 : BGN 1.9558
// 4 : CZK 27.54
// 5 : DKK 7.4432
// ------------
// Batch no: 2
// ------------
// 1 : GBP 0.7827
// 2 : HUF 312.18
// 3 : LTL 3.4528
// 4 : PLN 4.1827
// 5 : RON 4.4125
// ------------
// Batch no: 3
// ------------
// 1 : SEK 9.2018
// 2 : CHF 1.2071