Using CompareTo() to sort based on multiple columns

Jason picture Jason · Jun 23, 2009 · Viewed 9.7k times · Source

Currently I have an object implementing the IComparable interface (ASP.NET 3.5, VB). When I place several instantiated objects into a Generics list, I sort them by doing a simple someList.Sort. My CompareTo() function is this:

Public Function CompareTo(ByVal obj As Object) As Integer Implements 
System.IComparable.CompareTo
    'default is number of votes (opposite direction, highest first)'
    Dim sent As Sentence = CType(obj, Sentence)
    Return Not Points.CompareTo(sent.Points)
End Function

This works fine, except now I need to sort by another property, the DateSubmitted property, as a subset of the Points. For example, if three sentences have votes: 3, 1, 1, I want the one with the highest votes first (obviously) and of the two sentences with one vote, the one submitted the earliest to be listed.

Is this possible with CompareTo(), or should I just hit the database again and sort it there?

Thanks

Answer

Joel Coehoorn picture Joel Coehoorn · Jun 23, 2009

Your CompareTo() function is incorrect. You need to return correct results for three states (<, =, and >), and your Not means the function only correctly handles two of them. This will cause problems if you call the function on a large enough list.

As MehrdadA already mentioned, .Net 3.5 has a simpler way to handle it. But here's how to do it if for some reason you can't handle the lambda expressions:

Public Function CompareTo(Of Sentence)(ByVal obj As Sentence) As Integer _
  Implements System.IComparable.CompareTo(Of Sentence)

    If obj Is Nothing Return 1
    Dim result As Integer = Points.CompareTo(obj.Points) * -1
    If result = 0 Then result = DateSubmitted.CompareTo(obj.DateSubmitted)
    Return result
End Function

Note that you now want to implement IComparable(Of T), rather than IComparable.