Some Common GroupBy Operations on List<> using LINQ

Posted by: Suprotim Agarwal , on 1/21/2009, in Category LINQ
Views: 56414
Abstract: The ‘GroupBy’ feature in LINQ is amazing and very powerful. In this article, we will see some common GroupBy operations using LINQ.
Some Common GroupBy Operations on List<> using LINQ
 
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 is an 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 Birthdays 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.
C#
    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' });
 
            // Printing the List
            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; }
    }
     
 
VB.NET
Module Module1
 
    Sub Main()
        Dim empList As New List(Of Employee)()
        empList.Add(New Employee() With {.ID = 1, .FName = "John", .MName = "", .LName = "Shields", .DOB = DateTime.Parse("12/11/1971"), .Sex = "M"c})
        empList.Add(New Employee() With {.ID = 2, .FName = "Mary", .MName = "Matthew", .LName = "Jacobs", .DOB = DateTime.Parse("01/17/1961"), .Sex = "F"c})
        empList.Add(New Employee() With {.ID = 3, .FName = "Amber", .MName = "Carl", .LName = "Agar", .DOB = DateTime.Parse("12/23/1971"), .Sex = "M"c})
        empList.Add(New Employee() With {.ID = 4, .FName = "Kathy", .MName = "", .LName = "Berry", .DOB = DateTime.Parse("11/15/1976"), .Sex = "F"c})
        empList.Add(New Employee() With {.ID = 5, .FName = "Lena", .MName = "Ashco", .LName = "Bilton", .DOB = DateTime.Parse("05/11/1978"), .Sex = "F"c})
        empList.Add(New Employee() With {.ID = 6, .FName = "Susanne", .MName = "", .LName = "Buck", .DOB = DateTime.Parse("03/7/1965"), .Sex = "F"c})
        empList.Add(New Employee() With {.ID = 7, .FName = "Jim", .MName = "", .LName = "Brown", .DOB = DateTime.Parse("09/11/1972"), .Sex = "M"c})
        empList.Add(New Employee() With {.ID = 8, .FName = "Jane", .MName = "G", .LName = "Hooks", .DOB = DateTime.Parse("12/11/1972"), .Sex = "F"c})
        empList.Add(New Employee() With {.ID = 9, .FName = "Robert", .MName = "", .LName = "", .DOB = DateTime.Parse("06/28/1964"), .Sex = "M"c})
        empList.Add(New Employee() With {.ID = 10, .FName = "Cindy", .MName = "Preston", .LName = "Fox", .DOB = DateTime.Parse("01/11/1978"), .Sex = "M"c})
 
        ' Printing the List
        Console.WriteLine(Constants.vbLf & "{0,2} {1,7}    {2,8}      {3,8}      {4,23}      {5,3}", "ID", "FName", "MName", "LName", "DOB", "Sex")
        empList.ForEach(AddressOf AnonymousMethod1)
 
        Console.ReadLine()
    End Sub
 
    Private Sub AnonymousMethod1(ByVal e As Employee)
        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)
    End Sub
 
End Module
 
Friend Class Employee
    Private privateID As Integer
    Public Property ID() As Integer
        Get
            Return privateID
        End Get
        Set(ByVal value As Integer)
            privateID = value
        End Set
    End Property
    Private privateFName As String
    Public Property FName() As String
        Get
            Return privateFName
        End Get
        Set(ByVal value As String)
            privateFName = value
        End Set
    End Property
    Private privateMName As String
    Public Property MName() As String
        Get
            Return privateMName
        End Get
        Set(ByVal value As String)
            privateMName = value
        End Set
    End Property
    Private privateLName As String
    Public Property LName() As String
        Get
            Return privateLName
        End Get
        Set(ByVal value As String)
            privateLName = value
        End Set
    End Property
    Private privateDOB As DateTime
    Public Property DOB() As DateTime
        Get
            Return privateDOB
        End Get
        Set(ByVal value As DateTime)
            privateDOB = value
        End Set
    End Property
    Private privateSex As Char
    Public Property Sex() As Char
        Get
            Return privateSex
        End Get
        Set(ByVal value As Char)
            privateSex = value
        End Set
    End Property
End Class
Print Raw List
 
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
C#
    // Group People by the First Letter of their FirstName
    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();
VB.NET
        ' Group People by the First Letter of their FirstName
        Dim grpOrderedFirstLetter = empList.GroupBy(Function(employees) New String(employees.FName(0), 1)).OrderBy(Function(employees) employees.Key.ToString())
 
 
        For Each employee In grpOrderedFirstLetter
            Console.WriteLine(Constants.vbLf & "'Employees having First Letter {0}':", employee.Key.ToString())
            For Each empl In employee
                Console.WriteLine(empl.FName)
            Next empl
        Next employee
 
        Console.ReadLine()
 
First Letter Group
 
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
C#
            // Group People by the Year in which they were born           
            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();
VB.NET
        ' Group People by the Year in which they were born           
        Dim grpOrderedYr = empList.GroupBy(Function(employees) employees.DOB.Year).OrderBy(Function(employees) employees.Key)
 
        For Each employee In grpOrderedYr
            Console.WriteLine(Constants.vbLf & "Employees Born In the Year " & employee.Key)
            For Each empl In employee
                Console.WriteLine("{0,2} {1,7}", empl.ID, empl.FName)
            Next empl
        Next employee
        Console.ReadLine()
Print Year Group
 
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
C#
           // Group people by the Year and Month in which they were born
            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();
VB.NET
        ' Group people by the Year and Month in which they were born
        Dim grpOrderedYrMon = empList.GroupBy(Function(employees) New DateTime(employees.DOB.Year, employees.DOB.Month, 1)).OrderBy(Function(employees) employees.Key)
 
 
        For Each employee In grpOrderedYrMon
            Console.WriteLine(Constants.vbLf & "Employees Born in Year {0} - Month {1} is/are :", employee.Key.Year, employee.Key.Month)
            For Each empl In employee
                Console.WriteLine("{0}: {1}", empl.ID, empl.FName)
            Next empl
        Next employee
        Console.ReadLine()
Print Year Month Group
 
4. Total No. Of Birthdays each Year
To get a total of the employees born in the same year, use this query
C#
           // Count people grouped by the Year in which they were born
            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();   
VB.NET
        ' Count people grouped by the Year in which they were born
        Dim grpCountYrMon = empList.GroupBy(Function(employees) employees.DOB.Year).Select(Function(lst) New With {Key .Year = lst.Key, Key .Count = lst.Count()})
 
        For Each employee In grpCountYrMon
            Console.WriteLine(Constants.vbLf & "{0} were born in {1}", employee.Count, employee.Year)
        Next employee
        Console.ReadLine()
Total Yr Count
 
5. Sex Ratio
To find the sex ratio in the company, use this query
C#
            // Sex Ratio
            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(); 
VB.NET        ' Sex Ratio
        Dim ratioSex = empList.GroupBy(Function(ra) ra.Sex).Select(Function(emp) New With {Key .Sex = emp.Key, Key .Ratio = (emp.Count() * 100) / empList.Count})
 
        For Each ratio In ratioSex
            Console.WriteLine(Constants.vbLf & "{0} are {1}%", ratio.Sex, ratio.Ratio)
        Next ratio
        Console.ReadLine()
 Sex Ratio
Well I hope you got a fair bit of idea of the power of a GroupBy in LINQ and so did Linda, our fictional HR J. So Happy LINQing and keep practising! I hope you liked the article and I thank you for viewing it. The entire source code of this article in C# and VB.NET can be downloaded over here.

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of DotNetCurry, DNC Magazine for Developers, SQLServerCurry and DevCurry. He has also authored a couple of books 51 Recipes using jQuery with ASP.NET Controls and The Absolutely Awesome jQuery CookBook.

Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.

Get in touch with him on Twitter @suprotimagarwal or at LinkedIn



Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Shuaib on Wednesday, January 21, 2009 3:04 PM
Thanks for these great posts!!!
They are just awsome!
Comment posted by Donald on Wednesday, January 21, 2009 5:35 PM
Thanks for these great examples.
Comment posted by Suprotim Agarwal on Thursday, January 22, 2009 11:53 AM
Shuaib, Donald: Glad your liked them!
Comment posted by Makhor on Monday, January 26, 2009 9:47 AM
Another very good article. Your approach is so simple. Thanks.
Comment posted by ramani sandeep on Friday, September 18, 2009 7:39 AM
very good article ,
i really enjoyed it by practicing it side by side while i read
keep writing such useful articles.

Regards
(sandy)