Alexis Shepard Alexis Shepard - 2 months ago 9
Vb.net Question

Sorting List(Of T) stopping early



I have a custom class called SaveFile. One property it has is SaveNumber and I'm trying to sort the list by that property. I read a bunch of articles here and got it to sort properly but it's stopping early? The case in which I noticed this is with set that has 79 saves. It would sort: 1, 2, 3, 4, 5, 6, 7, 10, 11, ... 30, 8, 31, ... 70, 9, 71, .. The code I use is

saveList.Sort(Function(x, y) x.CompareTo(y)
)

But if I use the code:

For i = 0 To 3
saveList.Sort(Function(x, y) x.CompareTo(y))
Next


then it sorts right but it takes a very long time and one set has over 700 SaveFiles in it so it takes almost 5 minutes for my program to load. Any ideas?

This is the code that I have for my CompareTo function:

Public Function CompareTo(y As SaveFile) As Integer Implements IComparable(Of SaveFile).CompareTo



'If neither are an autosave then compare save number
If Not Me.Text.StartsWith("autosave") And Not y.Text.StartsWith("autosave") Then

If Me.SaveNumber.ToString.Length > y.SaveNumber.ToString.Length Then
Return False
ElseIf Me.SaveNumber.ToString.Length < y.SaveNumber.ToString.Length Then
Return True
End If

Return Me.SaveNumber < y.SaveNumber
'if either is an autosave
Else
'Create to comparable integers with
'a value of 4. We set the value to
'4 because it is higher than the 3
'available autosaves, making it sort
'after any autosaves if only one is
'an autosave.
Dim xComp As Integer = 4
Dim yComp As Integer = 4

'If x is an autosave then figure out
'which autosave number it is.
If Me.Text.StartsWith("autosave") Then
Select Case True
Case Me.Text.EndsWith("1")
xComp = 1
Case Me.Text.EndsWith("2")
xComp = 2
Case Me.Text.EndsWith("3")
xComp = 3
End Select
End If

'if y is an autosave then figure out
'which autosave number it Is.
If y.Text.StartsWith("autosave") Then
Select Case True
Case y.Text.EndsWith("1")
yComp = 1
Case y.Text.EndsWith("2")
yComp = 2
Case y.Text.EndsWith("3")
yComp = 3
End Select
End If

Return xComp < yComp
End If
End Function

Answer

First, asking 2 questions in one post is not a good idea because it reduces the chances someone will know the answer to both. For example, without seeing the code that loads these things or even what they are, makes it just a guess why it takes so long to load.

For the sorting, your CompareTo method is flawed. From MSDN:

Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.

That is, it should return -1 (precedes), 1 (follows) or 0 (same). Yours just returns Boolean:

If Me.SaveNumber.ToString.Length > y.SaveNumber.ToString.Length Then
    Return False
ElseIf Me.SaveNumber.ToString.Length < y.SaveNumber.ToString.Length Then
    Return True
End If
...
Return xComp < yComp

We have no idea what type SaveNumber is, but if it is am integer, comparing the length of the string form if it is not the same as comparing the value:

' Me vs Other
Return "9".Length < "7".Length

That will return False (0) when it by value, it should return 1. Turning on Option Strict would have flagged the incorrect return type, which might have led you to the answer. It should be something like this, ignoring the "auto" logic:

Public Function CompareTo(other As SaveItem) As Integer _
                  Implements IComparable(Of SaveItem).CompareTo

    ... special handling for "auto"

    If Me.SaveNumber = other.SaveNumber Then
        Return 0
    ElseIf Me.SaveNumber < other.SaveNumber Then
        Return -1
    Else
        Return 1
    End If

End Function

But, you may not even need that (assuming again that SaveNumber is an int):

saveItems = saveItems.OrderBy(Function(q) q.SaveNumber).ToList()

IComparable.CompareTo() might be needed in order to handle the "autosave" logic but it might be able to be handled in the OrderBy() depending on the information the class exposes.