DEV Community

Digionix
Digionix

Posted on

IComparable vs IComparer

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.

Alt Text

Which will result to a sorted list:

Alt Text

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.
Alt Text

Now let's create 6 students and put them into a list of students.
Alt Text

Then let's print out the list and sort it by their Age using the built in Sort function.
Alt Text
Alt Text
We were able to print it, but what's that?
Alt Text

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.
Alt Text

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:
Alt Text

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
Alt Text

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:
Alt Text

Which results in:
Alt Text
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
Alt Text

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.
Alt Text

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:
Alt Text

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:

Alt Text

Now let's print out the result:
Alt Text

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:
Alt Text

Printing out the result:
Alt Text

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)

Collapse
 
itstimey profile image
ItsTimey

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

Collapse
 
digionix profile image
Digionix

Thank you so much glad it helped you!

I am interested in writing more in the future, so we'll see I guess :)

Collapse
 
anhquanhua189 profile image
anhquanhua189 • Edited

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.

Collapse
 
digionix profile image
Digionix

Thank you for the suggestion! Much appreciated the time you took to think about it and I find it helpful :D

Collapse
 
jasonandrea profile image
Jason Andrea

Nice article! :) Like it

Collapse
 
digionix profile image
Digionix

Thank you! Glad you liked it

Collapse
 
rkynaa profile image
rkynaa

A great article! clear, simple

Collapse
 
digionix profile image
Digionix

Thank you!

Collapse
 
kj2whe profile image
Jason

A D@mn great article! My only suggestion is that you use the same test data set for IComparer as you did for IComparable.

Collapse
 
digionix profile image
Digionix

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 :-)