The ‘GroupBy’ feature in LINQ is amazing and very powerful. When you use a ‘GroupBy’ in LINQ, internally it calls an extension method which returns a sequence of System.Collections.Generic.IEnumerable<(Of <(IGrouping<(Of <(TKey, TSource>)>)>)>)
.
The GroupBy<(Of <(TSource, TKey>)>)(IEnumerable<(Of <(TSource>)>), Func<(Of <(TSource, TKey>)>))
method returns a collection of IGrouping<(Of <(TKey, TElement>)>)
objects, one for each distinct key that was encountered. The key represents the attribute that is common to each value in the IGrouping<(Of <(TKey, TElement>)>)
and can be accessed using a ForEach
loop.
In order to understand GroupBy
in LINQ, let’s take an example. Linda works in HR in a small private firm. To facilitate the HR process, she wants a simple console application to obtain some quick results. She needs the following details of Employees
:
- Raw List of
Employees
- List of
Employees
grouped by the first letter of their FirstName
- List of
employees
grouped by the Year
in which they were born
- List of
employees
grouped by the Year
and Month
in which they were born
- Total count of
employees
having Birthday
s in the same Year
- Sex Ratio
Let’s take these requirements one by one and see how they can be easily achieved using the ‘GroupBy
’ in LINQ. We will first create a simple list of employees (List<Employees>)
and add some data to it.
class Program
{
static void Main(string[] args)
{
List<Employee> empList = new List<Employee>();
empList.Add(new Employee() { ID = 1,
FName = "John", MName = "", LName = "Shields",
DOB = DateTime.Parse("12/11/1971"), Sex = 'M' });
empList.Add(new Employee() { ID = 2, FName = "Mary",
MName = "Matthew", LName = "Jacobs", DOB = DateTime.Parse("01/17/1961"),
Sex = 'F' });
empList.Add(new Employee() { ID = 3, FName = "Amber", MName = "Carl",
LName = "Agar", DOB = DateTime.Parse("12/23/1971"), Sex = 'M' });
empList.Add(new Employee() { ID = 4, FName = "Kathy", MName = "",
LName = "Berry", DOB = DateTime.Parse("11/15/1976"), Sex = 'F' });
empList.Add(new Employee() { ID = 5, FName = "Lena", MName = "Ashco",
LName = "Bilton", DOB = DateTime.Parse("05/11/1978"), Sex = 'F' });
empList.Add(new Employee() { ID = 6, FName = "Susanne", MName = "",
LName = "Buck", DOB = DateTime.Parse("03/7/1965"), Sex = 'F' });
empList.Add(new Employee() { ID = 7, FName = "Jim", MName = "",
LName = "Brown", DOB = DateTime.Parse("09/11/1972"), Sex = 'M' });
empList.Add(new Employee() { ID = 8, FName = "Jane", MName = "G",
LName = "Hooks", DOB = DateTime.Parse("12/11/1972"), Sex = 'F' });
empList.Add(new Employee() { ID = 9, FName = "Robert", MName = "",
LName = "", DOB = DateTime.Parse("06/28/1964"), Sex = 'M' });
empList.Add(new Employee() { ID = 10, FName = "Cindy", MName = "Preston",
LName = "Fox", DOB = DateTime.Parse("01/11/1978"), Sex = 'M' });
Console.WriteLine("\n{0,2} {1,7} {2,8} {3,8} {4,23} {5,3}",
"ID", "FName", "MName", "LName", "DOB", "Sex");
empList.ForEach(delegate(Employee e)
{
Console.WriteLine("{0,2} {1,7} {2,8} {3,8} {4,23} {5,3}",
e.ID, e.FName, e.MName, e.LName, e.DOB, e.Sex);
});
Console.ReadLine();
}
class Employee
{
public int ID { get; set; }
public string FName { get; set; }
public string MName { get; set; }
public string LName { get; set; }
public DateTime DOB { get; set; }
public char Sex { get; set; }
}
1. List of Employees Grouped by the First Letter of their FirstName
To display a list of employees
group by the first alphabet of their FirstName
, use this query.
var grpOrderedFirstLetter = empList.GroupBy(employees =>
new String(employees.FName[0], 1)).OrderBy(employees => employees.Key.ToString());;
foreach (var employee in grpOrderedFirstLetter)
{
Console.WriteLine("\n'Employees having First Letter {0}':", employee.Key.ToString());
foreach (var empl in employee)
{
Console.WriteLine(empl.FName);
}
}
Console.ReadLine();
2. List of Employees Grouped by the Year in Which they were Born
In order to group the employees based on the year in which they were born, use this query.
var grpOrderedYr = empList.GroupBy(
employees => employees.DOB.Year).OrderBy(employees => employees.Key);
foreach (var employee in grpOrderedYr)
{
Console.WriteLine("\nEmployees Born In the Year " + employee.Key);
foreach (var empl in employee)
{
Console.WriteLine("{0,2} {1,7}", empl.ID, empl.FName);
}
}
Console.ReadLine();
3. List of Employees Grouped by the Year and Month in Which they were Born
In order to group the employees
based on the year and then the month in which they were born, use this query.
var grpOrderedYrMon = empList.GroupBy(employees =>
new DateTime(employees.DOB.Year,
employees.DOB.Month, 1)).OrderBy(employees => employees.Key); ;
foreach (var employee in grpOrderedYrMon)
{
Console.WriteLine(
"\nEmployees Born in Year {0} - Month {1} is/are :",
employee.Key.Year, employee.Key.Month);
foreach (var empl in employee)
{
Console.WriteLine("{0}: {1}", empl.ID, empl.FName);
}
}
Console.ReadLine();
4. Total Number of Birthdays Each Year
To get a total of the employees
born in the same year, use this query.
var grpCountYrMon = empList.GroupBy(employees => employees.DOB.Year)
.Select(lst => new {Year = lst.Key, Count = lst.Count()} );
foreach (var employee in grpCountYrMon)
{
Console.WriteLine("\n{0} were born in {1}",employee.Count, employee.Year);
}
Console.ReadLine();
5. Sex Ratio
To find the sex ratio in the company, use this query.
var ratioSex = empList.GroupBy(ra => ra.Sex)
.Select( emp => new
{
Sex = emp.Key,
Ratio = (emp.Count() * 100) / empList.Count
});
foreach (var ratio in ratioSex)
{
Console.WriteLine("\n{0} are {1}%", ratio.Sex, ratio.Ratio);
}
Console.ReadLine();