Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / Win32

How To Sort Generic List?

Rate me:
Please Sign up or sign in to vote.
4.26/5 (11 votes)
12 Aug 2009CPOL2 min read 76.1K   455   26   10
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)


Written By
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 Pin
nguyenminhtien14119-Dec-11 19:09
nguyenminhtien14119-Dec-11 19:09 
GeneralAnother good article on the subject Pin
RTS@WORK9-Sep-09 3:43
RTS@WORK9-Sep-09 3:43 
GeneralRe: Another good article on the subject Pin
sognant17-Sep-09 23:49
sognant17-Sep-09 23:49 
GeneralI think this is a very good suggestion Pin
dbrenth19-Aug-09 3:38
dbrenth19-Aug-09 3:38 
This helped me a bunch. I was looking at having to deal with 8 IComparable Classes and calling each one from another one. Not everyone's sorting algorithm is a simple one line string compare like the other posters seem to claim. I have to go through an 8 or 9 step process to break the "ties". The code just looks much more readable (not to mention reusable) doing it the way you show here.

Thanks

[Edit:] Your employee class does NOT have to inherit from IComparable<> to use your methods. (You probably know that, but other readers may not notice that you removed the need for this inheritance and your article doesn't state that.)
GeneralRe: I think this is a very good suggestion Pin
Anand Malli19-Aug-09 20:35
Anand Malli19-Aug-09 20:35 
GeneralIt's actually not necessary to create and maintain zillions of static helper methods. Pin
Michael Epner18-Aug-09 4:03
Michael Epner18-Aug-09 4:03 
GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. Pin
Rich Visotcky18-Aug-09 4:54
Rich Visotcky18-Aug-09 4:54 
GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. Pin
Asher Barak17-Sep-09 3:59
professionalAsher Barak17-Sep-09 3:59 
GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. Pin
Rich Visotcky21-Sep-09 5:20
Rich Visotcky21-Sep-09 5:20 
GeneralRe: It's actually not necessary to create and maintain zillions of static helper methods. Pin
Asher Barak23-Sep-09 21:24
professionalAsher Barak23-Sep-09 21:24 

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

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