All About Sorting in C#

Introduction

This article explains all the comparison options available in C#. We will go through IComparable<> and IComparer<> first. Then we will move to other options provided by C#.

Problem

The first question is when to use what option. Well there is lots of scope. But why do we need those? Suppose we have an Employee class as follows:  
  1. public class Employee   
  2. {   
  3.      public string Name { getset; }   
  4.      public double Salary { getset; }   
  5.      public override string ToString()   
  6.      {   
  7.          return this.Name;   
  8.      }   
  9. }  

If we have a collection of Employee classes and want to sort it based on Name then if we try:

  1. var empList = new List<Employee> { new Employee() { Name = "Bubu", Salary = 5000 }, new Employee() { Name = "Arunava", Salary = 10000 } };   
  2.  empList.Sort();   
  3.  empList.ForEach(e => Console.WriteLine(e));  

We will get a run-time exception. The runtime doesn't read your mind and is unable to determine what logic to use to sort the list. So, the solution provided by C# is to implement IComparable<> or IComparer<>.

Differences between IComparable<> and IComparer<>

If the requirement is to sort the employees always by one property then in this case say by Name, then we can use IComparable<>. That means:

  1. public class Employee : IComparable<Employee>   
  2. {   
  3.      public string Name { getset; }   
  4.      public int Salary { getset; }   
  5.      public int CompareTo(Employee other)   
  6.      {   
  7.          return this.Name.CompareTo(other.Name);   
  8.      }   
  9.    
  10.      public override string ToString()       
  11.      {   
  12.          return this.Name;   
  13.      }   
  14. }   

And the main program will be:

  1. var empList = new List<Employee> { new Employee() { Name = "Bubu", Salary = 5000 }, new Employee() { Name = "Arunava", Salary = 10000 } };   
  2.  empList.Sort();   
  3.  empList.ForEach(e => Console.WriteLine(e));  

Now you will not get any exception and get your desired result. But sometimes we need to sort the collection differently, such as sort by Name and sort by Salary. Then we need to implement IComparer<>. But we need to have two different implementations as follows:

  1. public class EmployeeSortByName : IComparer<Employee>   
  2. {   
  3.      public int Compare(Employee x, Employee y)   
  4.      {   
  5.          return x.Name.CompareTo(y.Name);   
  6.      }   
  7. }   
  8.    
  9. public class EmployeeSortBySal : IComparer<Employee>   
  10. {   
  11.      public int Compare(Employee x, Employee y)   
  12.      {   
  13.          return x.Salary.CompareTo(y.Salary);   
  14.      }   
  15. }  

And use it as:

  1. var empList = new List<Employee> { new Employee() { Name = "Bubu", Salary = 10000 }, new Employee() { Name = "Arunava", Salary = 5000 } };   
  2.  empList.Sort(new EmployeeSortBySal()); or empList.Sort(new EmployeeSortByName());   
  3.  empList.ForEach(e => Console.WriteLine(e));  

This is another problem since we need to create multiple compare classes for different sorting.

Easier way

There is a better solution provided by C#, that is to use a Comparison<T> delegate. It is simple to use and see the power of it. It just removes all the code and reduces it to this:

  1. empList.Sort((x,y)=>x.Name.CompareTo(y.Name));  

Or:

  1. empList.Sort((x,y)=>x.Salary.CompareTo(y.Salary));  
If you want to order it by ascending or descending, you can use the OrderBy() extension as follows: 
  1. var eres=empList.OrderBy(x=>x.Name).ToList();   
  2.  eres.ForEach(e => Console.WriteLine(e));  

Or:

  1. var eres=empList.OrderBy(x=>x.Salary).ToList();   
  2.  eres.ForEach(e => Console.WriteLine(e));  

Happy coding.