Grouping Operators in LINQ

by Sachin Singh


Posted on Saturday, 06 February 2021

Tags: GroupBy in Linq Group By multiple keys in linq

How to think
How to think when working with LINQ

In LINQ, GroupBy operator is used to breakdown a collection into one or more groups based on a specific Key. The LINQ group by is different from what we have in SQL . In SQL we use a group by along with an aggregate function , but in Linq an aggregate function is not necessary , here we can simply make several groups based on a specific key out of a collection of items or objects. The diagram shown below explains the concept in a better manner.

GroupBy extension method
GroupBy extension method

I have already explained that all Linq operators are extension method of IEnumerable<T> type which accepts either Func, Predicate or Action generic delegate. The GroupBy() extension method accepts a Func<Source,Key> generic delegate.

As you can see , GroupBy is an extension method on IEnumerable<T> which accepts Func generic delegate , we already know a delegate can point to any method of same signature so we can either define an external method of same signature or we can use lambda expression to define a delegate inline.

Examples of Linq GroupBy in Method Syntax

Following are the examples of using LINQ GroupBy in method syntax.

Example : Group employee by Gender and Marital status.

Method 1. With external function.


       public class Employee
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Phone { get; set; }
            public string Gender { get; set; }
            public string MaritalStatus { get; set; }
        }


    public class Program
    {
        public static void Main()
        {
            List<Employee> emploees = new List<Employee>() 
            {
                new Employee(){Id=1,Name="Sachin",Gender="Male",MaritalStatus="UnMarried",Phone=123456},
                 new Employee(){Id=2,Name="Arjun",Gender="Male",MaritalStatus="UnMarried",Phone=123457},
                 new Employee(){Id=3,Name="Vikash",Gender="Male",MaritalStatus="UnMarried",Phone=123458},
                 new Employee(){Id=4,Name="Neha",Gender="Female",MaritalStatus="UnMarried",Phone=123459},
                 new Employee(){Id=5,Name="Nivi",Gender="Female",MaritalStatus="UnMarried",Phone=123450},
                 new Employee(){Id=6,Name="Abhijeet",Gender="Male",MaritalStatus="Married",Phone=123451},
                 new Employee(){Id=7,Name="Ankit",Gender="Male",MaritalStatus="Married",Phone=123452}
            };
            var EmpGroupByGender = emploees.GroupBy(KeyIsGender);
            foreach (var group in EmpGroupByGender)
            {
                Console.WriteLine("______________________________");
                Console.WriteLine("group by: "+group.Key);
                Console.WriteLine("______________________________");
                foreach (var employee in group)
                {
                    Console.WriteLine(employee.Name);
                    Console.WriteLine(employee.MaritalStatus);
                    Console.WriteLine(employee.Phone);
                    Console.WriteLine("...................");
                }
                Console.WriteLine("______________________________");
                Console.WriteLine("Next Group starts from here");
                Console.WriteLine("______________________________");
            }
               
     var EmpGroupByMaritalStatus = emploees.GroupBy(KeyIsMaritalStatus);
            foreach (var group in EmpGroupByGender)
            {
                Console.WriteLine("______________________________");
                Console.WriteLine("group by: " + group.Key);
                Console.WriteLine("______________________________");
                foreach (var employee in group)
                {
                    Console.WriteLine(employee.Name);
                    Console.WriteLine(employee.MaritalStatus);
                    Console.WriteLine(employee.Phone);
                    Console.WriteLine("...................");
                }
                Console.WriteLine("______________________________");
                Console.WriteLine("Next Group starts from here");
                Console.WriteLine("______________________________");
            }
            Console.ReadLine();
        }

        public static string KeyIsGender(Employee emp)
         {          
                 return emp.Gender;           
        }
        public static string KeyIsMaritalStatus(Employee emp)
        {
            return emp.MaritalStatus;
        }

Method 2. With lambda expression.


   public class Program
    {
        public static void Main()
        {
            List<Employee> emploees = new List<Employee>() 
            {
                new Employee(){Id=1,Name="Sachin",Gender="Male",MaritalStatus="UnMarried",Phone=123456},
                 new Employee(){Id=2,Name="Arjun",Gender="Male",MaritalStatus="UnMarried",Phone=123457},
                 new Employee(){Id=3,Name="Vikash",Gender="Male",MaritalStatus="UnMarried",Phone=123458},
                 new Employee(){Id=4,Name="Neha",Gender="Female",MaritalStatus="UnMarried",Phone=123459},
                 new Employee(){Id=5,Name="Nivi",Gender="Female",MaritalStatus="UnMarried",Phone=123450},
                 new Employee(){Id=6,Name="Abhijeet",Gender="Male",MaritalStatus="Married",Phone=123451},
                 new Employee(){Id=7,Name="Ankit",Gender="Male",MaritalStatus="Married",Phone=123452}
            };

            var EmpGroupByGender = emploees.GroupBy(x=>x.Gender);
            foreach (var group in EmpGroupByGender)
            {
                Console.WriteLine("______________________________");
                Console.WriteLine("group by: "+group.Key);
                Console.WriteLine("______________________________");
                foreach (var employee in group)
                {
                    Console.WriteLine(employee.Name);
                    Console.WriteLine(employee.MaritalStatus);
                    Console.WriteLine(employee.Phone);
                    Console.WriteLine("...................");
                }
                Console.WriteLine("______________________________");
                Console.WriteLine("Next Group starts from here");
                Console.WriteLine("______________________________");
            }

            var EmpGroupByMaritalStatus = emploees.GroupBy(x => x.MaritalStatus);
            foreach (var group in EmpGroupByGender)
            {
                Console.WriteLine("______________________________");
                Console.WriteLine("group by: " + group.Key);
                Console.WriteLine("______________________________");
                foreach (var employee in group)
                {
                    Console.WriteLine(employee.Name);
                    Console.WriteLine(employee.MaritalStatus);
                    Console.WriteLine(employee.Phone);
                    Console.WriteLine("...................");
                }
                Console.WriteLine("______________________________");
                Console.WriteLine("Next Group starts from here");
                Console.WriteLine("______________________________");
            }
            Console.ReadLine();
        }
  }

Output

Group By operator
GroupBy operator in Linq

If you observe in the above example, we are grouping "Employee" collection items based on Employee MaritalStatus and Gender.

Examples of LINQ GroupBy in Query Syntax

Let's achieve the same using Query Syntax


   public static void Main()
        {
            List<Employee> emplyoees = new List<Employee>() 
            {
                new Employee(){Id=1,Name="Sachin",Gender="Male",MaritalStatus="UnMarried",Phone=123456},
                 new Employee(){Id=2,Name="Arjun",Gender="Male",MaritalStatus="UnMarried",Phone=123457},
                 new Employee(){Id=3,Name="Vikash",Gender="Male",MaritalStatus="UnMarried",Phone=123458},
                 new Employee(){Id=4,Name="Neha",Gender="Female",MaritalStatus="UnMarried",Phone=123459},
                 new Employee(){Id=5,Name="Nivi",Gender="Female",MaritalStatus="UnMarried",Phone=123450},
                 new Employee(){Id=6,Name="Abhijeet",Gender="Male",MaritalStatus="Married",Phone=123451},
                 new Employee(){Id=7,Name="Ankit",Gender="Male",MaritalStatus="Married",Phone=123452}
            };

            var EmpGroupByGender = from emp in emplyoees
                                   group emp by emp.Gender into eGroup
                                   select eGroup;

            foreach (var group in EmpGroupByGender)
            {
                Console.WriteLine("______________________________");
                Console.WriteLine("group by: "+group.Key);
                Console.WriteLine("______________________________");
                foreach (var employee in group)
                {
                    Console.WriteLine(employee.Name);
                    Console.WriteLine(employee.MaritalStatus);
                    Console.WriteLine(employee.Phone);
                    Console.WriteLine("...................");
                }
                Console.WriteLine("______________________________");
                Console.WriteLine("Next Group starts from here");
                Console.WriteLine("______________________________");
            }

            var EmpGroupByMaritalStatus = from emp in emplyoees
                                          group emp by emp.MaritalStatus into eGroup
                                          select eGroup;
            foreach (var group in EmpGroupByGender)
            {
                Console.WriteLine("______________________________");
                Console.WriteLine("group by: " + group.Key);
                Console.WriteLine("______________________________");
                foreach (var employee in group)
                {
                    Console.WriteLine(employee.Name);
                    Console.WriteLine(employee.MaritalStatus);
                    Console.WriteLine(employee.Phone);
                    Console.WriteLine("...................");
                }
                Console.WriteLine("______________________________");
                Console.WriteLine("Next Group starts from here");
                Console.WriteLine("______________________________");
            }
            Console.ReadLine();
        }

Output

Group By operator
GroupBy operator in Linq

This is how we can use LINQ GroupBy in method syntax and query syntax to group a list or collection of items , the only difference with query syntax is, we have to use into keyword to project collection to a group.

Group By Multiple Keys

In the previous example we groped employees by their Gender and Marital status , but in real time we may need to group first by Gender and then inside the gender Group again group them by marital status. If it doesn't make sense to you then follow the diagram shown below.

Group By operator with multiple keys
GroupBy operator in Linq with multiple keys

In order to group by multiple keys we use anonymous type as shown below

Example : Group employees by Gender and then by MaritalStatus.


     public static void Main()
        {
            List<Employee> employees = new List<Employee>() 
            {
                new Employee(){Id=1,Name="Sachin",Gender="Male",MaritalStatus="UnMarried",Phone=123456,Salary=20000},
                 new Employee(){Id=2,Name="Arjun",Gender="Male",MaritalStatus="UnMarried",Phone=123457,Salary=30000},
                
                 new Employee(){Id=3,Name="Neha",Gender="Female",MaritalStatus="UnMarried",Phone=123459,Salary=50000},
                 new Employee(){Id=4,Name="Nivi",Gender="Female",MaritalStatus="UnMarried",Phone=123450,Salary=60000},

                 new Employee(){Id=5,Name="Abhijeet",Gender="Male",MaritalStatus="Married",Phone=123451,Salary=70000},
                 new Employee(){Id=6,Name="Ankit",Gender="Male",MaritalStatus="Married",Phone=123452,Salary=80000},

                 new Employee(){Id=7,Name="Nidhi",Gender="Female",MaritalStatus="Married",Phone=123458,Salary=40000},
                 new Employee(){Id=8,Name="Supriya",Gender="Female",MaritalStatus="Married",Phone=123458,Salary=47000},
            };
            var employeeGroups = employees
                                        .GroupBy(x => new { x.Gender, x.MaritalStatus})
                                        .OrderBy(g => g.Key.Gender).ThenBy(g => g.Key.MaritalStatus)
                                        .Select(g => new
                                        {
                                            Gender = g.Key.Gender,
                                            MaritalStatus = g.Key.MaritalStatus,
                                            Employees = g.OrderBy(x => x.Name)
                                        });

            foreach (var group in employeeGroups)
            {
                Console.WriteLine("Gender: {0} MaritalStatus: {1} employees count: {2}",
                    group.Gender, group.MaritalStatus, group.Employees.Count());
                Console.WriteLine("--------------------------------------------");
                foreach (var employee in group.Employees)
                {
                    Console.WriteLine(employee.Id+"\t"+employee.Name + "\t" + employee.Gender
                        + "\t" + employee.Salary);
                }
                Console.WriteLine(); Console.WriteLine();
            }
            Console.ReadLine();
        }

Output

Group By Multiple Keys
Group By Multiple Keys output

Example 2: Rewrite Example 1 using SQL like syntax


     public static void Main()
        {
            List<Employee> employees = new List<Employee>() 
            {
                new Employee(){Id=1,Name="Sachin",Gender="Male",MaritalStatus="UnMarried",Phone=123456,Salary=20000},
                 new Employee(){Id=2,Name="Arjun",Gender="Male",MaritalStatus="UnMarried",Phone=123457,Salary=30000},
                
                 new Employee(){Id=3,Name="Neha",Gender="Female",MaritalStatus="UnMarried",Phone=123459,Salary=50000},
                 new Employee(){Id=4,Name="Nivi",Gender="Female",MaritalStatus="UnMarried",Phone=123450,Salary=60000},

                 new Employee(){Id=5,Name="Abhijeet",Gender="Male",MaritalStatus="Married",Phone=123451,Salary=70000},
                 new Employee(){Id=6,Name="Ankit",Gender="Male",MaritalStatus="Married",Phone=123452,Salary=80000},

                 new Employee(){Id=7,Name="Nidhi",Gender="Female",MaritalStatus="Married",Phone=123458,Salary=40000},
                 new Employee(){Id=8,Name="Supriya",Gender="Female",MaritalStatus="Married",Phone=123458,Salary=47000},
            };
            var employeeGroups = from employee in employees
                                 group employee by new
                                 {
                                     employee.Gender,
                                     employee.MaritalStatus
                                 } into eGroup
                                 orderby eGroup.Key.Gender ascending,
                                               eGroup.Key.MaritalStatus ascending
                                 select new
                                 {
                                     Gender = eGroup.Key.Gender,
                                     MaritalStatus = eGroup.Key.MaritalStatus,
                                     Employees = eGroup.OrderBy(x => x.Name)
                                 };

            foreach (var group in employeeGroups)
            {
                Console.WriteLine("Gender: {0} MaritalStatus: {1} employees count: {2}",
                    group.Gender, group.MaritalStatus, group.Employees.Count());
                Console.WriteLine("--------------------------------------------");
                foreach (var employee in group.Employees)
                {
                    Console.WriteLine(employee.Id+"\t"+employee.Name + "\t" + employee.Gender
                        + "\t" + employee.Salary);
                }
                Console.WriteLine(); Console.WriteLine();
            }
            Console.ReadLine();
        }

Output

Group By Multiple Keys
Group By Multiple Keys output