What is grouped data and why would we want grouped data? Well, for one, grouped data is much easier to analyse. Grouping also enables us conveniently to analyse or summarize the data. Well, it just happens that grouping is a very cool and powerful feature of LINQ.

So, to jump right into it, here’s a simple grouping of employees by seniority. Consider the following array:

private readonly Employee[] employees = new[]
{
    new Employee () { Id = 1, Email = "a@google.net", Name = "Homer Simpson", Status = 1, Seniority = Seniority.Manager },
    new Employee () { Id = 2, Email = "nec.malesuada@icloud.edu", Name = "Justina Merritt", Status = 1, Seniority = Seniority.Junior},
    new Employee () { Id = 3, Email = "florrick@icloud.edu", Name = "Justina Florrick", Status = 1, Seniority = Seniority.Junior},
    new Employee () { Id = 4, Email = "jtimberla.ke@icloud.edu", Name = "Justin Timberlake", Status = 1, Seniority = Seniority.Senior},
    new Employee () { Id = 5, Email = "risus.quis.diam@icloud.com", Name = "Gabriel Dawson", Status = 2, Seniority = Seniority.Lead},
    new Employee () { Id = 6, Email = "at.iaculis@yahoo.org", Name = "Caldwell Kirkland", Status = 3, Seniority = Seniority.Senior},
};

Here’s how we group those employees by Seniority – a simple property of the Employee:

var employeesBySeniority = employees
    .GroupBy(e => e.Seniority)
    .OrderByDescending(group => group.Key);

foreach (var seniorityGroup in employeesBySeniority)
{
    Console.WriteLine($"Key: {seniorityGroup.Key}");

    foreach (var employee in seniorityGroup)
    {
        Console.WriteLine($"\t{employee.Name} ({employee. Email})");
    }
}

Outputs:

Key: Manager
	Homer Simpson (a@google.net)
Key: Lead
	Gabriel Dawson (risus.quis.diam@icloud.com)
Key: Senior
	Justin Timberlake (jtimberla.ke@icloud.edu)
	Caldwell Kirkland (at.iaculis@yahoo.org)
Key: Junior
	Justina Merritt (nec.malesuada@icloud.edu)
	Justina Florrick (florrick@icloud.edu)

But we do not necessarily need to Group by a simple property. We can group by computed value.

For example, here we would group our employees be the domain of the E-mail address they use, without having to create a separate property:

var employeesByEmailDomain = employees
    .Select(employee => new { 
        Employee = employee, 
        Domain = employee.Email.Split("@")[1] 
    })
    .GroupBy(e => e.Domain)
    .Select(employeeGrouping => new {
        Domain = employeeGrouping.Key,
        Employees = employeeGrouping.Select(e => new { e.Employee.Name, e.Employee.Email, e.Employee.Seniority })
    })
    .OrderBy(e => e.Domain);

foreach (var domainGroup in employeesByEmailDomain)
{
    Console.WriteLine($"Domain: {domainGroup.Domain}");

    foreach (var employee in domainGroup.Employees)
    {
        Console.WriteLine($"\t{employee.Name} ({employee.Email}), {employee. Seniority}");
    }
}

Output:

Domain: google.net
	Homer Simpson (a@google.net), Manager
Domain: icloud.com
	Gabriel Dawson (risus.quis.diam@icloud.com), Lead
Domain: icloud.edu
	Justina Merritt (nec.malesuada@icloud.edu), Junior
	Justina Florrick (florrick@icloud.edu), Junior
	Justin Timberlake (jtimberla.ke@icloud.edu), Senior
Domain: yahoo.org
	Caldwell Kirkland (at.iaculis@yahoo.org), Senior

We can even do something more complex, like grouping by a key that contains muötipöe vaöues. For example, here we would group by seniority and a first letter of the name:

var employeesByFirstLetterAndSeniority = employees
    .GroupBy(e => new { FirstLetter = e.Name[0], e.Seniority})
    .OrderBy(e => e.Key.Seniority)
    .ThenBy(e => e.Key.FirstLetter);

foreach (var scoreGroup in employeesByFirstLetterAndSeniority)
{
    Console.WriteLine($"Seniority Level {scoreGroup.Key.Seniority}, Name starts with {scoreGroup.Key.FirstLetter}");

    foreach (var item in scoreGroup)
    {
        Console.WriteLine($"\t{item.Name} ({item.Email})");
    }
}

Here is our output:

Seniority Level Junior, Name starts with J
	Justina Merritt (nec.malesuada@icloud.edu)
	Justina Florrick (florrick@icloud.edu)
Seniority Level Senior, Name starts with C
	Caldwell Kirkland (at.iaculis@yahoo.org)
Seniority Level Senior, Name starts with J
	Justin Timberlake (jtimberla.ke@icloud.edu)
Seniority Level Lead, Name starts with G
	Gabriel Dawson (risus.quis.diam@icloud.com)
Seniority Level Manager, Name starts with H
	Homer Simpson (a@google.net)

That is it for this introductory post into grouping with LINQ. Be sure to return for our Part II where we will take a look at some advanced grouping tips and tricks.

Until next time, develop clerly, code smart and stay safe.