Sorting issues with IComparer

rbulph

Junior Contributor
Joined
Feb 17, 2003
Messages
397
I've got a List of objects that I need to sort. There's a variety of criteria for the order that I want to sort them into, and for some of them I simply want the existing order to be maintained. For these objects I have no other record of their appropriate order than the order they are contained in in the List, and I want to preserve this. To sort them it seems sensible to use a class implementing IComparer, but the problem is, if I just return 0 for these items that I don't want sorting, they get sorted anyway (I'm not quite sure in accordance with what). So I've solved the problem by making a copy of the List before I do the sort and looking at the position of items in that. But it would be better if I didn't have to make this copy. Can you see a way around this?

Here's some simple code so that you can see what I've done:

Code:
Public Class Form1
    Friend p As New List(Of String)
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        p.Add("Mouse")
        p.Add("Manatee")
        p.Add("Mole")
        p.Add("Ant")
        p.Add("Bee")
        p.Add("Walrus")
        p.Add("Monitor Lizard")

        Dim p2 As New List(Of String)

        For Each s As String In p
            p2.Add(s)
        Next

        p.Sort(New consorter(p2))

        For Each i As String In p
            Debug.Print(i)
        Next

    End Sub

    Private Class consorter

        'A class to sort a List of strings alphabetically, provided that if they begin with the same letter, they remain in the same order as before.
        Implements Collections.Generic.IComparer(Of String)

        Private presortlist As List(Of String)
        Friend Sub New(ByVal p As List(Of String))
            presortlist = p
        End Sub

        Public Function Compare(ByVal x As String, ByVal y As String) As Integer Implements System.Collections.Generic.IComparer(Of String).Compare

            If x = y Then Return 0
            Dim Dif As Integer = Asc(x.Chars(0)) - Asc(y.Chars(0))
            If Dif = 0 Then
                Return presortlist.IndexOf(x) - presortlist.IndexOf(y)  'if I just return 0 here then the order of things beginning with "M" gets changed.
            Else
                Return Dif
            End If

        End Function

    End Class
End Class
 
Returning 0 simply means the two items you are comparing are equal, this however doesn't make any claims about the items position in the sorted list.

i.e. If you say "Mouse" and "Manatee" are to be treated as equal by your sorting routine then Mouse, Manatee or Manatee, Mouse are both valid orderings for the results.

The exact order would depend on the internal sorting algorithm used by Array.Sort - which is really an implementation detail and cannot be relied upon as this could change in future anyway.

If you want to maintain an explicit order you would either need to handle this yourself or include the current position in the IComparer comparison.
 
Back
Top