Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

How To Sort Generic List?

4.26/5 (11 votes)
12 Aug 2009CPOL2 min read 77.5K   459  
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.

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

C#
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).

C#
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.)

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

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

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

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

C#
/// <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)