Sort list items with iComparer and iComparable

Sorting primitive data is easy. The list has the method "Sort()" for sorting items in ascending order. And we can use the Reverse() function after sorting to get the list in descending order. Let's first sort simple data types using the Sort method.

You might have come across a problem where you want to sort items in a list without writing your own sorting algorithm. Fear not, C# has (List, ArrayList) that implements a sorting algorithm for us. But how do we actually use it? We will talk about the different approaches we can take to sort items in the list.

Primitive Types :
Sorting primitive data is easy. The list has the method "Sort()" for sorting items in ascending order. And we can use the Reverse() function after sorting to get the list in descending order. Let's first sort simple data types using the Sort method.

static void Main() {

    // create list of numbers
    List < int > numbers = new List < int > () {
      1,
      43,
      12,
      553,
      21,
      66,
      7,
      0,
      112
    };

    // create list of alphabets
    List < string > alphabets = new List < string > () {
      "X",
      "F",
      "B",
      "A",
      "G",
      "D"
    };

    /* ----------- sorts item in ascending order -------------- */
    numbers.Sort // sorts numbers in ascending order
    alphabets.Sort(); // sorts alphabets in ascending

    Console.WriteLine("number in ascending order ..........."; foreach(int item in numbers) {
          Console.WriteLine("items is " + item);
        }

        Console.WriteLine("string in ascending order ..........."; foreach(string item in alphabets) {
            Console.WriteLine("items is " + item);
          }

And for descending order we simply call a reverse method like this:

numbers.Reverse();
alphabets.Reverse();

Console.WriteLine("number in descending order ..........."; foreach(int item in numbers) {
      Console.WriteLine("items is " + item);
    }

    Console.WriteLine("string in descending order ..........."; foreach(string item in alphabets) {
        Console.WriteLine("items is " + item);
      }
    }

Complex Types :
Well, sorting primitive types was nice and easy but what about complex types that contains multiple data types inside. Simply using the sort method for sorting complex types will throw an error. Let's look at what happens when we use Sort for complex type. Let's make a simple class called Fruit

public class Fruit {
  public string name;
  public int price;
}

List < Fruit > fruits = new List < Fruit > () {
  new Fruit("kiwi", 30),
    new Fruit("orannge", 10),
    new Fruit("apple", 20),
    new Fruit("banana", 40)
}

fruits.Sort(); // error

IComparable :

The above code will throw an error saying the class must implement IComparable because of List.Sort() internally calls  CompareTo() method to sort items. So we need to implement an IComparable interface in the Fruit class. Let's see how we can do it using IComparer.

public class Fruit: IComparable {
  public string name;
  public int price;

  public int CompareTo(Object obj) {

    int value = price - ((Fruit) obj).price; // this will make sorting ascending

    // int value =((Fruit)obj).price - price; // this will make sorting descending

    return value;

  }

  public override string ToString() {
    return $ "Name : {name} , Price : {price}";
  }
}

Now using fruits.Sort() will sort item. You can always use your own logic inside the CompareTo function to make how the sorting is done. Swapping the order in which difference is taken will produce a different result.

IComparer :

If The class does not inherit the IComparable interface and we are not able to add it to our class then sorting will fail again. For this matter, we use another interface called IComparable.It has a function to compare items called "Compare" which takes 2 objects as arguments. We then compare those 2 objects according to our requirement and pass them to the list sort method. This will help in sorting any type of object. Let's look at how we can do it using IComparer. Before sorting we need to first create a class that inherits from IComparer. Let's see how we can do it in example:

public class FruitComparer: IComparer < Fruit > {

  public int Compare(Fruit x, Fruit y) {

    // we compare name of the fruit x with name of fruit y
    return x.name.CompareTo(y.name);
  }
}

Now, sorting can be done by first creating the object of the FruitComparer and pass it as an argument in the Sort function.

FruitComparer fruitComparer = new FruitComparer();

fruits.Sort(fruitComparer);

Console.WriteLine("Sorted fruits with name is ........")

foreach(var fruit in fruits) {
  Console.WriteLine(fruit.ToString());
}

Things to know :

  • primitive types can be sorted automatically by using the Sort method in the list.
  • For complex types, we need either IComparable or IComparer for sorting to work.
  • IComparable interface is implemented inside the type we want to sort.
  • IComparable has a method CompareTo that take one argument which can be compared with the current object to provide ¬†either a positive or negative number
  • IComparer on the other hand should be implemented separately in a different class and should specify what type of object can be compared. It takes 2 arguments to compare with each other.
  • We then use our own logic to compare items inside IComparer or IComparable interface implementation.
  • If an object has implemented IComparable, it doesn't require any argument but if it has implemented IComparer, we need to pass IComparer as an argument in the Sort method.