Click here to Skip to main content
Click here to Skip to main content
Go to top

How To Sort Generic List?

, 12 Aug 2009
Rate this:
Please Sign up or sign in to vote.
An article on sorting generic list based on any attribute of user defined class

Introduction

Some time ago, I was asked a question related to generic List<T>. How to sort any generic list based on some data member of any user defined class. Let me admit that I have been using C#.NET since the last 3 years but at that moment nothing comes into my mind directly. There is a method named Sort() - that's what the first thought was. So thereafter I tried it by making a sample application. There are various ways to achieve it but with this small article I am posting my solution which I think is very simple.

Background 

First let's understand the problem with one simple example. Let's say we are having a list of employees for some organization. Now to generate a report, there are few requirements to sort that list name-wise or employeeid-wise, etc. So our problem is how to achieve it via generic list so that very limited changes allow us to sort it on any of the attributes.

Using the Code

Let's have a user defined Employee class.

public class Employee
    {
        #region Private Members

        private Int32 empId;
        private String empName;
        private DateTime empJoiningDate;

        #endregion

        #region Properties

        public Int32 EmployeeId
        {
            get { return empId; }
            set { empId = value; }
        }

        public String EmployeeName
        {
            get { return empName; }
            set { empName = value; }
        }

        public DateTime EmployeeJoiningDate
        {
            get { return empJoiningDate; }
            set { empJoiningDate = value; }
        }

        #endregion
    }

Now whenever we want to use the sorted Employee list, first of all we will create the List<T>.

List<Employee> myEmployeeList = new List<Employee>();

The next step would be using the Sort() method & inside the method writing another easy-to-find method CompareTo(). But the problem with this approach is that sometimes we have to specify that sorting has to be based on some specific attributes only (i.e. ID or Name of the employees).

public int CompareTo(Employee other)
{
    return EmployeeName.CompareTo(other.EmployeeName);
}

The above method can be useful only when we are sure about the attribute for which sorting is to be done. Otherwise it's better to have the parameter to be passed for sorting. To achieve this, we should use IComparable<T>. (Click here for details.)

public class Employee : IComparable<Employee>
{
    [...]
       
    public Int32 CompareTo(Employee other)
    {
        return EmployeeName.CompareTo(other.EmployeeName);
    }            
       
    [...]
}

Here we are having fix attribute Name for sorting. To add flexibility, we can use delegates to avoid the code repetition. We can declare multiple delegates for each attribute upon which sorting is allowed.

public class Employee : IComparable<Employee>
{
    [...]
       
    /// <summary>
    /// Comparison of age between the employees.
    /// </summary>
    public static Comparison<Employee> AgeComparison = 
				delegate(Employee p1, Employee p2)
    {
        return p1.empAge.CompareTo(p2.empAge);
    };
        
    /// <summary>
    /// Comparison of name between the employees.
    /// </summary>
    public static Comparison<Employee> NameComparison = 
				delegate(Employee p1, Employee p2)
    {
        return p1.empName.CompareTo(p2.empName);
    };           
       
    [...]
}

By declaring static delegates, we can use them without creating the instance of Employee class while passing as parameter to Sort() method.

myEmployeeList.Sort(Employee.NameComparison);
[...]
myEmployeeList.Sort(Employee.AgeComparison);

Let's have a look at the full code of Employee class:

/// <summary>
/// This class represents the structure, group of this structure is to be sorted.
/// </summary>
public class Employee : IComparable<Employee>
{
    #region Private Members

    private Int32 empId;
    private String empName;
    private UInt32 empAge;

    #endregion
  
    #region Properties
        
    /// <summary>
    /// Gets or sets the employee id / no
    /// </summary>
    public Int32 EmployeeId
    {
        get { return empId; }
        set { empId = value; }
    }

    /// <summary>
    /// Gets or sets the name of the employee
    /// </summary>
    public String EmployeeName
    {
        get { return empName; }
        set { empName = value; }
    }

    /// <summary>
    /// Gets or sets the Age of the employee
    /// </summary>
    public UInt32 EmployeeAge
    {
       get { return empAge; }
       set { empAge = value; }
    }

    #endregion

    #region Constructor
          
    /// <summary>
    /// Creates an instance of an employee class.
    /// </summary>
    /// <param name="id"> Id / no of the employee to be created.</param>
    /// <param name="name">Name of the employee to be created.</param>
    /// <param name="age">Age of the employee to be created.</param>
    public Employee(Int32 id, String name, UInt32 age)
    {
        this.empId = id;
        this.empName = name;
        this.empAge = age;
    }
        
    #endregion

    #region Static Members
    /// <summary>
    /// Comparison of age between the employees.
    /// </summary>
    public static Comparison<Employee> AgeComparison = delegate(Employee p1, Employee p2)
    {
        return p1.empAge.CompareTo(p2.empAge);
    };

    /// <summary>
    /// Comparison of name between the employees.
    /// </summary>
    public static Comparison<Employee> NameComparison = delegate(Employee p1, Employee p2)
    {
        return p1.empName.CompareTo(p2.empName);
    };

    /// <summary>
    /// Comparison of employee Id / No between the employees.
    /// </summary>
    public static Comparison<Employee> IDComparison = delegate(Employee p1, Employee p2)
    {
        return p1.empId.CompareTo(p2.empId);
    };

    #endregion

    #region IComparable<Product> Members
          
    /// <summary>
    /// Compares the current employee object with another object of the same type.
    /// </summary>
    /// <param name="other">An employee object to compare with this object</param>
    /// <returns>A 32-bit signed integer that indicates 
    /// the relative order of the objects being compared.</returns>
    public Int32 CompareTo(Employee other)
    {
        return EmployeeName.CompareTo(other.EmployeeName);
    }

    #endregion

    #region Overridden Methods
           
    /// <summary>
    /// Gets a canonical string representation for the specified employee instance.
    /// </summary>
    /// <returns>A System.String instance that contains the unescaped 
    /// canonical representation of the employee instance</returns>
    public override string ToString()
    {
        return string.Format("Id: {0} Name: {1} Age: {2}", empId, empName, empAge);
    }

    #endregion
}

History

  • 12th August, 2009 -- Article submitted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Anand Malli
Software Developer (Senior)
India India
Anand has been designing and developing applications using C# and the .NET framework since last 3 years.
 
When he's not writing code, you can catch him taking snaps or lost in playing computer games.

Comments and Discussions

 
GeneralMy vote of 5 Pinmembernguyenminhtien14119-Dec-11 19:09 
GeneralAnother good article on the subject PinmemberRTS@Orix9-Sep-09 3:43 
GeneralRe: Another good article on the subject Pinmembersognant17-Sep-09 23:49 
GeneralI think this is a very good suggestion Pinmemberdbrenth19-Aug-09 3:38 
GeneralRe: I think this is a very good suggestion PinmemberAnand Malli19-Aug-09 20:35 
GeneralIt's actually not necessary to create and maintain zillions of static helper methods. PinmemberMichael Epner18-Aug-09 4:03 
It's actually not necessary to create and maintain zillions of static helper methods.
 

.NET 2.0:
 
 
myEmployeesList.Sort(delegate(Employee x, Employee y) { return x.No.CompareTo(y.No); });
 
myEmployeesList.Sort(delegate(Employee x, Employee y) { return StringComparer.CurrentCultureIgnoreCase.Compare(x.Name, y.Name); });
 
 

 
.NET 3.x:
 
 
myEmployeesList.Sort((x, y) => x.No.CompareTo(y.No); });
 
myEmployeesList.Sort((x, y) => StringComparer.CurrentCultureIgnoreCase.Compare(x.Name, y.Name); });
 

GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. PinmemberRich Visotcky18-Aug-09 4:54 
GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. PinmemberAsher Barak17-Sep-09 3:59 
GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. PinmemberRich Visotcky21-Sep-09 5:20 
GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. PinmemberAsher Barak23-Sep-09 21:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 12 Aug 2009
Article Copyright 2009 by Anand Malli
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid