LINQ GroupBy

Summary: in this tutorial, you’ll learn how to use the LINQ GroupBy() method to group the elements of a sequence based on a key.

The GroupBy() method groups elements in a sequence based on a specified key. The method returns a sequence of groups, where each element implements the IGrouping(TKey, TElement> interface.

The GroupBy() method has several overloads, and each has a specific purpose. We’ll introduce to you some of the GroupBy() overloads with examples.

A simple LINQ GroupBy() method

Here’s the syntax of the GroupBy() method:

IGrouping<TKey,TElement> GroupBy<TSource, TKey>(
    IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector
);Code language: C# (cs)

In this syntax:

  • TSource is the type of elements of the source sequence.
  • TKey is the key returned by the keySelector function.
  • TElement is the type of elements in the IGrouping<TKey, TElement>.
  • source is the input sequence that has the IEnumerable<TSource>.
  • keySelector is a function that selects the key for each element.
  • elementSelector is a function that maps each element to an element in the IGrouping<TKey, TElement>.

The GroupBy() by method returns a sequence of elements with the type of IGrouping<TKey, TElement>.

The following example uses the GroupBy() method to group a list of students into groups specified by courses of the students:

class Student
{
    public string? Name { get; set; }
    public string? Course { get; set; }
    public int Age { get; set; }

}

class Program
{
    public static void Main(string[] args)
    {

        // Create a list of students
        var students = new List<Student>()
        {
            new Student { Name = "John", Course = "C#", Age = 25 },
            new Student { Name = "Jane", Course = "C#", Age = 22 },
            new Student { Name = "Bob", Course = "Javascript", Age = 20 },
            new Student { Name = "Alice", Course = "Javascript", Age = 21 }
        };

        // Group the students by course
        var groups = students.GroupBy(s => s.Course);

        // Show the groups
        foreach (var group in groups)
        {
            Console.WriteLine(group.Key + ":");
            foreach (var student in group)
            {
                Console.WriteLine("- " + student.Name + " (" + student.Age + ")");
            }
            Console.WriteLine();
        }

    }
}Code language: C# (cs)

Output:

C#:
- John (25)
- Jane (22)

Javascript:
- Bob (20)
- Alice (21)Code language: C# (cs)

How it works.

First, define a Student class that has three properties Name, Course, and Age:

class Student
{
    public string? Name { get; set; }
    public string? Course { get; set; }
    public int Age { get; set; }
}Code language: C# (cs)

Second, create a list that has four Student objects:

var students = new List<Student>()
{
    new Student { Name = "John", Course = "C#", Age = 25 },
    new Student { Name = "Jane", Course = "C#", Age = 22 },
    new Student { Name = "Bob", Course = "Javascript", Age = 20 },
    new Student { Name = "Alice", Course = "Javascript", Age = 21 }
};Code language: C# (cs)

Third, use the GroupBy() method to group the students by courses:

var groups = students.GroupBy(s => s.Course);Code language: C# (cs)

Finally, show the groups to the Console:

foreach (var group in groups)
{
    Console.WriteLine(group.Key + ":");
    foreach (var student in group)
    {
        Console.WriteLine("- " + student.Name + " (" + student.Age + ")");
    }
    Console.WriteLine();
}Code language: C# (cs)

Using the LINQ GroupBy() method with an element selector

The following overload of the GroupBy() method has a second delegate that allows you to select the elements of the groups:

IGrouping<TKey,TElement> GroupBy<TSource, TKey, TElement>(
   IEnumerable<TSource> source, 
   Func<TSource, TKey> keySelector, 
   Func<TSource, TElement> elementSelector
);Code language: C# (cs)

For example:

using static System.Console;
class Student
{
    public string? Name { get; set; }
    public string? Course { get; set; }
    public int Age { get; set; }
}
class Program
{
    public static void Main(string[] args)
    {

        // Create a list of students
        var students = new List<Student>()
        {
            new Student { Name = "John", Course = "C#", Age = 25 },
            new Student { Name = "Jane", Course = "C#", Age = 22 },
            new Student { Name = "Bob", Course = "Javascript", Age = 20 },
            new Student { Name = "Alice", Course = "Javascript", Age = 21 }
        };

        // Group the students by course
        var groups = students.GroupBy(s => s.Course, s=> s.Name);

        // Show the groups
        foreach (var group in groups)
        {
            WriteLine($"{group.Key}:");
            foreach (var name in group)
            {
                WriteLine($"- {name}");
            }
            WriteLine();
        }

    }
}Code language: C# (cs)

Output:

C#:
- John
- Jane

Javascript:
- Bob
- AliceCode language: C# (cs)

In this example, we use the elementSelector function to select the elements for each group. More specifically, we select the name of each student as the element of the result sequence.

Using the LINQ GroupBy() method with an equality comparer

The following overload of the GroupBy() method allows you to specify an instance of IEqualityComparer<TKey> to compare keys for equality:

IGrouping<TKey,TElement> GroupBy<TSource, TKey, TElement>(
   IEnumerable<TSource> source, 
   Func<TSource, TKey> keySelector, 
   Func<TSource, TElement> elementSelector,
   IEqualityComparer<TKey>? comparer
);Code language: C# (cs)

This overload is useful when you want to have a specific equality comparer that fits your scenario.

For example, the following uses the GroupBy() method with a CourseComparer that compares two course case-insensitively:

using static System.Console;
class Student
{
    public string? Name { get; set; }
    public string? Course { get; set; }
    public int Age { get; set; }
}

class CourseComparer : IEqualityComparer<string?>
{
    public bool Equals(string? x, string? y)
    {
        if (x == null || y == null)
            return false;

        return x.ToLower() == y.ToLower();
    }

    public int GetHashCode(string obj)
    {
        return obj.ToLower().GetHashCode();
    }
}

class Program
{
    public static void Main(string[] args)
    {

        // Create a list of students
        var students = new List<Student>()
        {
            new Student { Name = "John", Course = "C#", Age = 25 },
            new Student { Name = "Jane", Course = "c#", Age = 22 },
            new Student { Name = "Bob", Course = "Javascript", Age = 20 },
            new Student { Name = "Alice", Course = "JAVASCRIPT", Age = 21 }
        };

        var groups = students.GroupBy(s => s.Course, new CourseComparer());

        // Display the groups
        foreach (var group in groups)
        {
            WriteLine($"{group.Key}:");
            foreach (var student in group)
            {
                WriteLine($"- {student.Name} ({student.Age})");

            }
            WriteLine();
        }

    }
}Code language: C# (cs)

Output:

C#:
- John (25)
- Jane (22)

Javascript:
- Bob (20)
- Alice (21)Code language: C# (cs)

In this example, the course names are not standardized. Some courses are in upper case while others are not:

var students = new List<Student>()
{
    new Student { Name = "John", Course = "C#", Age = 25 },
    new Student { Name = "Jane", Course = "c#", Age = 22 },
    new Student { Name = "Bob", Course = "Javascript", Age = 20 },
    new Student { Name = "Alice", Course = "JAVASCRIPT", Age = 21 }
};Code language: C# (cs)

The CourseComparer class compares two courses case-insensitively by converting them to lowercase before comparison:

class CourseComparer : IEqualityComparer<string?>
{
    public bool Equals(string? x, string? y)
    {
        if (x == null || y == null)
            return false;

        return x.ToLower() == y.ToLower();
    }

    public int GetHashCode(string obj)
    {
        return obj.ToLower().GetHashCode();
    }
}Code language: C# (cs)

The GroupBy() method uses an instance of the CourseComparer to group the students by the course names:

 var groups = students.GroupBy(s => s.Course, new CourseComparer());Code language: C# (cs)

Summary

  • Use the LINQ GroupBy() method to group elements in a sequence into groups by a specified key.
Was this tutorial helpful ?