Introduction
When doing sorting in C#, you will come across with the interface IComparable and IComparer.
Both of the interfaces are frequently used together, and people often got confused because of its similar name, even though they serve different purposes.
On this article, I will explain the difference between both of the IComparable and IComparer.
First, let us dive into the concept of sorting.
Assume that we have a list of integer that we want to sort in an ascending order.
Since we are using the data type Int and the built in List, we can use the provided Sort method by Microsoft.
Which will result to a sorted list:
This works because the Sort method knows what it has to sort, which in this case is an Integer number.
But, what if I want to sort a list that contains user-defined class?
Let's create a new class called Student, which will contain a name and age of a student.
Note: The age will be a random integer number between 17 to 50.
Now let's create 6 students and put them into a list of students.
Then let's print out the list and sort it by their Age using the built in Sort function.
We were able to print it, but what's that?
We got an error! "At least one object must implement IComparable"
This happens because the sorting algorithm doesn't know how to sort the elements. Which in this case is the Name of the student's class.
IComparable
To be able to sort it, we will have to implement the IComparable interface into our Student class.
So let's start by implementing it to our class.
Now because we implemented the interface, we will have to implement its method as well.
Here we will be overriding the CompareTo method.
The CompareTo method is used to compare one object with another object of the same type. It will then return an integer that indicates the position of the object in the sort order (precedes, follows, occurs)
If the current value is bigger than the next value it will return 1, else it will return -1. And if both of the value are the same it will return 0. It works like this:
- 1: Swap
- 0: Keep
- -1: Don't swap
For example, let's say that we have a List of [6,2,10,7,3].
Then we call the CompareTo method on the list, and it will compare the current item 6 with the next item 2.
Since 6 is bigger than 2, it will return the value 1. So both of the element will swap.
The list is now [2,6,10,7,3] and it will repeat the process again until it becomes [2,3,6,7,10].
Now let's fill in the CompareTo method:
What this does is that, it will compare the current Student age with the next Student age.
Let's try running the code and see what happens
It works! now the students are sorted beautifully based on their age.
We can also sort it by other data by modifying the CompareTo method. Let's try sorting it by their names now:
Which results in:
All sorted by their names cleanly!
IComparer
Now after understanding how IComparable works, we can go into how IComparer works.
IComparable allows you to sort on a user-defined class that you have full control in. But, what if you want to apply the sorting in a class you don't have control? Which means you can't change the implementation of the class.
For example, let's say that we don't have access to modify the student class
Right now, if we call the sort method, it will sort the student by their names.
Let's say that we want to sort it by their ages. But since we can't modify the Student class, we won't be able to modify the CompareTo method.
This is where IComparer comes in. We will have to create a new class that implements the IComparer interface.
Let's start by creating a new class then implement the IComparer interface.
Once we created the new class, we will need to implement its method called Compare.
The Compare method is used to perform a comparison between two objects with the same type. It will then return a value which will indicate if one object is less than, equal to, or greater than the other object.
<br
This is what it means by the returned value:
- Less than zero: x is less than y
- Zero: x equals y
- Greater than zero: x is greater than y
For example, let's say that we are comparing between two object 9 and 3.
When we are comparing it based on x - y, we will compare if 9 is bigger than 3, and since 9 is bigger than 3 it will return 1.
Let's fill in the Compare method now:
What this is saying is that we will compare the first student's age by the second student's age.
Then we will have to implement our new StudentComparer class into our sorting method by passing it as parameter:
Now let's print out the result:
Nice it's sorted by the student age!
It is sorted in an ascending order. But, what if we want to sort it in a descending order?
The Compare method can be modified to sort the objects to our liking. In this case its sorted in an ascending order because we are comparing it by x - y.
If we want to sort it in a descending order we will have to flip it into y - x.
Let's use an example to understand the positioning of x - y.
Assume that we want to sort a list of [8,5,9,7] in an ascending and descending order.
When we want to sort in ascending order it will be x - y. This is because when we take the first object 8 (x) and the second object 5 (y), we will compare them and since 8 is bigger it will return 1, which means that it will be swapped (Refer to IComparable rule above).
Now the list will be [5, 8, 9, 7]. Then we will keep comparing the object with the next object until the list becomes [5,7,8,9].
Now when we want to sort it in descending order it will be y - x.
Using the above list, we take the object y which is 5 and object x which is 8. Here we compare them and 5 is less than 8 so we will not swap them.
The list will stay as [8,5,9,7]. Then for the next comparison it will compare between object y which is 9 and object x which is 8.
9 is bigger than 8 so they will swap.
New list is now [9,5,8,7]. This comparison will keep repeating until we get a list of [9,8,7,5].
Let's try sorting the student age in descending order:
Great! It is now sorted in an descending order.
Summary
So that's how both IComparable and IComparer interface works.
I hope you are able to understand how they are different from each other, and how to use them.
Thank you and have a nice day!
Top comments (10)
A very helpful article! It makes me understand more about these two interfaces, at first I really don't understand anything about these interfaces. But after reading this for a while, I get to know more a little bit I guess hahah. Are you going to make more articles in the future ? Looking forward to more of this! :D
Thank you so much glad it helped you!
I am interested in writing more in the future, so we'll see I guess :)
Great article! A little suggestion, instead of using 'bigger' to describe the relationship between the items, we should just say that the item precedes or follows one another. This will just indicate the item's order with the specific comparer and save us some extra explanations.
Thank you for the suggestion! Much appreciated the time you took to think about it and I find it helpful :D
Nice article! :) Like it
Thank you! Glad you liked it
A great article! clear, simple
Thank you!
A D@mn great article! My only suggestion is that you use the same test data set for IComparer as you did for IComparable.
Thank you so much!
It does come into my mind to use the same data set for making it clearer but I wanted to show it working using the randomed values.
I do appreciate the suggestion though and I'll keep that in mind :-)