These are two interfaces that used to confuse me. I didn’t know when to use one or when to use the other. The aim of this post is to make it easier for someone to understand the differences and choose appropriately.

In as a few words as possible:
i)A class that implements IComparable can be sorted or compared to another class instance in a manner that you define.

ii)A class that implements IComparer can be used to sort or compare classes that do or do not implement IComparable.

The List.Sort() Method.

Every list(generic list, array, arraylist) has a built-in method called Sort(). The Sort() method knows how to sort all objects that implement the IComparable interface. The method uses an object’s CompareTo() method to compare it with other objects and use its return value to figure out which object comes first.

To sort objects that do not implement IComparable, you have the IComparer Interface. It’s used to assist the list’s Sort() method in sorting its members.

IComparable.
You implement this within the class you want to be sorted. The interface has only one method called CompareTo() that takes an object as a parameter, compares it with the class and returns an integer value that figures out which object comes first.

See the sample class below.

[sourcecode language=’VB’]
Public Class Person
Implements IComparable(Of Person)
‘these should be properties
Public FirstName As String
Public LastName As String
Public Age As Integer

Public Sub New(ByVal first As String, ByVal last As String, ByVal age As Integer)
Me.FirstName = first
Me.LastName = last
Me.Age = age
End Sub

Public Function fullName() As String
Return Me.FirstName & ” ” & Me.LastName & “: Age – ” & Me.Age
End Function

Public Function CompareTo(ByVal other As Person) As Integer Implements System.IComparable(Of Person).CompareTo
If Me.Age > other.Age Then
Return 1
ElseIf Me.Age < other.Age Then Return -1 Else Return 0 End If End Function End Class [/sourcecode] Notice the CompareTo() method. It takes another Person class as a parameter, compares the Ages and returns a number indicating which one comes first. In this method you can create any sorting logic that you need. You could for example compare by Age, FirstName or Lastname. In this sample the classes will be sorted by Age. Implementation:
One you have a list of objects that implement IComparable, all you have to do to sort them is just call the List.Sort() method without
passing any parameters. See sample code for a button bellow.

[sourcecode language=’VB’]
Dim list As List(Of Person)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
list = New List(Of Person)
list.Add(New Person(“Nick”, “Masao”, 27))
list.Add(New Person(“Sydney”, “Mtaita”, 3))
list.Add(New Person(“Ruth”, “Mtaita”, 23))

Debug.WriteLine(“”)
Debug.WriteLine(“Unsorted:”)
For Each p As Person In list
Debug.WriteLine(p.fullName)
Next

‘Just call the sort method without passing any parameters and you are done
‘The Sort() method uses the logic in the CompareTo() method in the class to ‘sort the list members

list.Sort()

Debug.WriteLine(“”)
Debug.WriteLine(“Sorted by Age:”)
For Each p As Person In list
Debug.WriteLine(p.fullName)
Next
End Sub
[/sourcecode]

The code produces the following output.
IComparable_Output
As you can see the objects were sorted by age.

IComparer.

Implement this in a class that you will use to sort other classes that may or may not implement IComparable. This class will be a ‘comparer’ and will impose the sorting order in the List.Sort() method. The interface has only one method called Compare() that takes two objects and returns a value which determines which object comes first.

To sort a list using IComparer, you need to create a new instance of the class that implements it and pass that instance to the List.Sort() method. The list object will then use the class’s Compare() method to sort the members.

Say for example you have a person class with the following definition.  Note that it doesn’t implement any interface.

[sourcecode language=’VB’]
Public Class Person
‘these should be properties
Public FirstName As String
Public LastName As String
Public Age As Integer

Public Sub New(ByVal first As String, ByVal last As String, ByVal age As Integer)
Me.FirstName = first
Me.LastName = last
Me.Age = age
End Sub

Public Function fullName() As String
Return Me.FirstName & ” ” & Me.LastName & “: Age – ” & Me.Age
End Function
End Class
[/sourcecode]

Now to use IComparer to sort a list of objects like the above, you need to create a simple class that implements IComparer and define the sorting manner, like so.

[sourcecode language=’VB’]
Public Class PersonComparer_ByAge
Implements IComparer(Of Person)

Public Function Compare(ByVal x As Person, ByVal y As Person) As Integer Implements System.Collections.Generic.IComparer(Of Person).Compare
If x.Age > y.Age Then
Return 1
ElseIf x.Age < y.Age Then Return -1 Else Return 0 End If End Function End Class [/sourcecode] The Class sorts the Person objects by Age. You could also sort by FirstName or LastName. The only limitation of IComparer is that it has access to public members of the class only. See another class that implements IComparer but this time sorts by the FirstName field. [sourcecode language='VB'] Public Class PersonComparer_ByFistName Implements IComparer(Of Person) Public Function Compare(ByVal x As Person, ByVal y As Person) As Integer Implements System.Collections.Generic.IComparer(Of Person).Compare If x.FirstName > y.FirstName Then
Return 1
ElseIf x.FirstName < y.FirstName Then Return -1 Else Return 0 End If End Function End Class [/sourcecode] Implementation:
If you have a list of objects, and you have a class that implements IComparer and has the sorting criteria like
the above class then you have to do the following to sort your list.

  1. Create an instance of your sorting class.
  2. Pass that instance to the list.sort() method.
  3. That’s it.

Sample button code that implements the code above.

[sourcecode language=’VB’]
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
list = New List(Of Person)
list.Add(New Person(“Nick”, “Masao”, 27))
list.Add(New Person(“Sydney”, “Mtaita”, 3))
list.Add(New Person(“Ruth”, “Mtaita”, 23))

Debug.WriteLine(“Unsorted:”)
For Each p As Person In list
Debug.WriteLine(p.fullName)
Next

Debug.WriteLine(“”)

‘instantiate the sorter/comparer class that implements IComparer

Dim sortName As New PersonComparer_ByFistName

‘pass it as criteria to the sort method

list.Sort(sortName)

Debug.WriteLine(“Sorted by Firstname:”)
For Each p As Person In list
Debug.WriteLine(p.fullName)
Next

Debug.WriteLine(“”)
‘instantiate the comparer class and pass it to the sort method
Dim sortAge As New PersonComparer_ByAge
list.Sort(sortAge)

Debug.WriteLine(“Sorted by Age:”)
For Each p As Person In list
Debug.WriteLine(p.fullName)
Next
End Sub
[/sourcecode]

The above code produces the following output.

IComparer_Output

Advantages & Limitations.

The advantage of IComparable is that you have access to the private members. i.e you can create your sorting criteria using private members in the class since the CompareTo() method is withing the class. The limitation is you only have that one way of sorting.

The limitation of IComparer is that the object that implements it doesn’t have access to private members of the objects it sorts. It only has access to public members.

Its advantages are, as seen in the sample code above, you can create a number of sorting options, and you have the option of passing the more specific and more appropriate sorting criteria to the Sort() method.

This post is getting too long  and I think I’ll end it here. Hopefully it was an eye opened of some sorts. Till next time, yours truly.

Sorting by IComparable vs IComparer
Tagged on:             

4 thoughts on “Sorting by IComparable vs IComparer

  • November 25, 2009 at 2:49 am
    Permalink

    This is very helpful. Thank you!

    What I’d like is to create my classes so that I can sort them by any property, and even multiple properties if necessary, such as by ObjectDate, ObjectTime, ObjectName. I’d like the method to be as generic as possible. Currently I create the class, and then create a collection that inherits the class:

    Public Class MyClass_Collection
    Inherits Collection(Of MyClass)
    End Class

    What I’d like is something to the effect of:

    MyClass.Sort(MyClass.Date, MyClass.Time, MyClass.Name)

    Result:

    1/1/2009, 1:00pm, Allen
    1/1/2009, 1:00pm, Betty
    1/1/2009, 1:01pm, Allen
    1/2/2009, 1:00pm, Allen

    What’s the best way to get that effect? Thanks again!

    🙂
    Mark

    Reply
  • November 25, 2009 at 2:52 am
    Permalink

    Please when you respond to my above question about how to create a generic class sort capability, please respond to this comment. I forgot to click the Notify By Email on the one above, and I’d very much like to be notified of the response. Thanks!

    Mark

    Reply
  • October 29, 2012 at 7:48 pm
    Permalink

    Many thanks.
    I have been struggling with the concept and use of these two interfaces for much too long. Finally my struggle has come to an end.
    I’m very grateful to you for this post and your willingness to share knowledge in such a clear way.

    Reply
  • December 28, 2012 at 4:21 am
    Permalink

    This article really clears up the confusion I have between the two. You did a fantastic job on the explanation. Thank you so much.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *