Using IComparable And IComparer Interfaces

Introduction

 
IComparable provides a method of comparing two objects of a particular type. This is necessary if we want to provide any ordering for our object. It defines an interface for an object with a CompareTo() method that returns an integer.
 
So, we could say that it provides a comparer check (for sorting) when there is only one way of ordering the objects (implemented inside the class)
IComparer, on the other hand, allows you to define and use multiple comparer checks (implemented outside the class) 
 
It defines an interface with a Compare() method that takes two objects of another type (which don't have to implement IComparable) and
compares them. 
 
Step 1
 
Add a class Student
  1. public class Student  
  2. {  
  3.    public int Roll_number;  
  4.    public string Name;  
  5.    public int Grade;  
  6. }  
Step 2
  1. public class Student_Collection  
  2. {  
  3.    public static void Main()  
  4.    {  
  5.       Student s1 = new Student() { Roll_number = 1, Name = "Avijit", Grade = 90 };  
  6.       Student s2 = new Student() { Roll_number = 3, Name = "Tirtha", Grade = 70 };  
  7.       Student s3 = new Student() { Roll_number = 2, Name = "Rajiv", Grade = 60 };  
  8.       Student s4 = new Student() { Roll_number = 4, Name = "Monosriz", Grade = 80 };  
  9.       List<Student> list = new List<Student>() { s1, s2, s3,s4 };  
  10.    
  11.       list.Sort();  
  12.       foreach (var student in list)  
  13.          Console.WriteLine("Roll Number : " + student.Roll_number + " " + "Name : " + student.Name + " " + "Grade : " + student.Grade);  
  14.       Console.ReadLine();  
  15.    }  
  16. }  
Note
We would get an exception while calling the Sort() method since we are trying to sort a complex type hereStudent and the compiler does not understand on which attribute it should sort the list.
 
But if the list had been an integer type then we might have not encountered the exception, since the list would have contained all integer values which are nothing but scalar values.
 
Solution
 
Use the IComparable interface for sorting Complex Type, it has CompareTo() method as a member as discussed. Say that we have type Student and want to compare two objects from this type according to their Roll_number. It would be more practical to implement the IComparable interface within the Student class.
 
Modify your existing Student Class, adding the IComparable interface and implementing the CompareTo() Method in it.
  1. public class Student : IComparable<Student>  
  2. {  
  3.    public int Roll_number;  
  4.    public string Name;  
  5.    public int Grade;  
  6.    public int CompareTo(Student other)  
  7.    {  
  8.       if (this.Roll_number > other.Roll_number)  
  9.          return 1;  
  10.       else if (this.Roll_number < other.Roll_number)  
  11.          return -1;  
  12.       else  
  13.       return 0;  
  14.    }  
  15. }  
Press F5 to run Student_Collection.
 
Output
 
In Ascending Order.
 
Roll Number : 1 Name : Avijit Grade : 90
Roll Number : 2 Name : Rajiv Grade : 60
Roll Number : 3 Name : Tirtha Grade : 70
Roll Number : 4 Name : Monosriz Grade : 80
 
For Descending after Sort() add Reverse()
  • list.Sort();
  • list.Reverse();
Now let's assume that we are getting the Student class form a .dll
 
As per the current requirement, it says we need to sort by Grade not by Roll_number to achieve that. However, we cannot modify the Student class since it's a part of .dll and we could only consume it but cannot modify it. What should we do?
 
Here, we can make use of IComparer as another interface.
 
Student class is a part of the dll, now giving us the behaviour of sorting the data by Roll_number
  1. public class Student : IComparable<Student>  
  2. {  
  3.    public int Roll_number;  
  4.    public string Name;  
  5.    public int Grade;  
  6.    public int CompareTo(Student other)  
  7.    {  
  8.       if (this.Roll_number > other.Roll_number)  
  9.          return 1;  
  10.       else if (this.Roll_number < other.Roll_number)  
  11.          return -1;  
  12.       else  
  13.          return 0;  
  14.    }  
  15. }  
Add a class and give it any name. Then implement the IComparer interface with Compare() method that implements the logic of sorting by Grade.
  1. class Compareby_Grade : IComparer<Student>  
  2. {  
  3.    public int Compare(Student x, Student y)  
  4.    {  
  5.       if (x.Grade > y.Grade)  
  6.          return 1;  
  7.       else if (x.Grade < y.Grade)  
  8.          return -1;  
  9.       else  
  10.          return 0;  
  11.    }  
  12. }  
  13.    
  14.    
  15. public class Student_Collection  
  16. {  
  17.    public static void Main()  
  18.    {  
  19.       Student s1 = new Student() { Roll_number = 1, Name = "Avijit", Grade = 90 };  
  20.       Student s2 = new Student() { Roll_number = 3, Name = "Tirtha", Grade = 70 };  
  21.       Student s3 = new Student() { Roll_number = 2, Name = "Rajiv", Grade = 60 };  
  22.       Student s4 = new Student() { Roll_number = 4, Name = "Monosriz", Grade = 80 };  
  23.       List<Student> list = new List<Student>() { s1, s2, s3,s4 };  
  24.       Compareby_Grade obj = new Compareby_Grade();  
  25.         
  26.       list.Sort(obj);       // Sort by Grade Ascending  
  27.       //list.Sort();           //Sort by Roll_number Ascending optional here as per the requirment  
  28.       list.Reverse();  //Use it for Descending  
  29.    
  30.       foreach (var student in list)  
  31.       Console.WriteLine("Roll Number : " + student.Roll_number + " " + "Name : " + student.Name + " " + "Grade : " + student.Grade);  
  32.       Console.ReadLine();  
  33.    }  
  34. }  
Press F5 to run Student_Collection again.
 
Running the program will eventually sort the list by Grade.
 
Happy Learning...