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.
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
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
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.
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
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