Search code examples
vb.netsortingarraylistversionicomparer

How to order an arraylist by versions or dot delimited in VB.NET


I have this kind of imput in my arraylist:

1
1.1
1.1.1
1.1.1.1
1.1.2
1.10
1.11
1.2
1.9

And I want to sort it, to get result looks like this:

1
1.1
1.1.1
1.1.1.1
1.1.2
1.2
1.9    
1.10
1.11

I have found possible solutions in other languages but it is difficult for me to understand them. I have this function that reads the file names of a folder without its extension but I don't know how to order them (I tried to treat them as decimals but it didn't work).

    Function GetVersions(ByVal mypath As String) As ArrayList
    Dim Versions As New ArrayList

    For Each Ver As String In My.Computer.FileSystem.GetFiles(mypath)
        If IsNumeric(Path.GetFileNameWithoutExtension(Ver)) Then
            Versions.Add(Decimal.Parse(Path.GetFileNameWithoutExtension(Ver)).ToString("#0.00")) 
        End If
    Next

    Dim mesg As String = ""
    For Each str As String In Versions
        mesg = mesg & str & vbCrLf
    Next
    MsgBox(mesg)

    Return Versions
    End Function

I am not very familiar with IComparer but I can implement it if I need it


Solution

  • The class in the example stores the version number as an encoded Long with each position being between 0 and 255, 8 bits. Probably a little overkill unless you have a whole lot of this ... ;)

    A form with a button is required,

    Public Class Form1
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Test of Class VersionNumber
            Dim l As New List(Of VersionNumber)
    
            Dim test As XElement = <t>
                                       <t>1.11</t>
                                       <t>1</t>
                                       <t>1.2</t>
                                       <t>1.2.3</t>
                                       <t>1.2.3.4</t>
                                       <t>1.1.3</t>
                                       <t>1.1.2</t>
                                       <t>1.10</t>
                                       <t>1.2.1</t>
                                       <t>1.2</t>
                                       <t>1.9</t>
                                       <t>1.2.3.4.5.6.7.8</t>
                                   </t>
    
            Debug.WriteLine("")
            Debug.WriteLine("")
            Dim foo As VersionNumber
            For Each el As XElement In test.Elements
                Debug.WriteLine(el.Value)
                foo = New VersionNumber(el.Value)
                l.Add(foo)
            Next
            l.Sort()
    
            Debug.WriteLine("")
            Debug.WriteLine("Sorted")
            For Each vn As VersionNumber In l
                Debug.WriteLine(vn.ToString)
            Next
        End Sub
    End Class
    
    Public Class VersionNumber
        Implements IComparable(Of VersionNumber), IEquatable(Of VersionNumber)
    
        Protected Friend _version As Long = 0L
        Private _verstring As String
    
        Public Sub New(Version As String)
            Dim prts() As String = Version.Trim.Split("."c)
            If prts.Length <= 0 OrElse prts.Length > 8 Then
                Throw New ArgumentException("Invalid version")
            Else
                Dim idx As Integer = 0
                Dim shft As Integer = 8 - (8 - (8 - prts.Length))
                Do While shft < 8
                    Dim L As Long = 0L
                    If Long.TryParse(prts(idx), L) AndAlso L >= 0 AndAlso L < 256L Then
                        shft += 1
                        idx += 1
                        Me._version = Me._version Or L
                        If shft <> 8 Then Me._version = Me._version << 8
                    Else
                        Throw New ArgumentException("Invalid version")
                    End If
                Loop
                Me._verstring = Version.Trim
                shft = (8 - (8 - (8 - prts.Length))) * 8
                Me._version = Me._version << shft
            End If
        End Sub
    
        Public Overrides Function ToString() As String
            Return Me._verstring
        End Function
    
    #Region " and Ops"
        Public Function CompareTo(other As VersionNumber) As Integer _
                    Implements IComparable(Of VersionNumber).CompareTo
            'https://msdn.microsoft.com/en-us/library/system.icomparable.compareto(v=vs.110).aspx
            'return values and their meaning:
            ' Less than zero      This instance precedes other in the sort order. 
            ' Zero                This instance occurs in the same position in the sort order as other. 
            ' Greater than zero   This instance follows other in the sort order. 
    
            If other Is Nothing Then
                Return 1 'By definition, any object compares greater than (or follows) null, and two null references compare equal to each other
            ElseIf Me = other Then
                Return 0
            ElseIf Me < other Then
                Return -1
            Else
                Return 1
            End If
        End Function
    
        Public Overloads Function Equals(other As VersionNumber) As Boolean _
                    Implements IEquatable(Of VersionNumber).Equals
    
            Select Case Me.CompareTo(other)
                Case 0
                    Return True
                Case Else
                    Return False
            End Select
        End Function
    
        Public Shared Operator =(VersNum1 As VersionNumber,
                                 VersNum2 As VersionNumber) As Boolean
            Return VersNum1._version.Equals(VersNum2._version)
        End Operator
    
        Public Shared Operator <>(VersNum1 As VersionNumber, VersNum2 As VersionNumber) As Boolean
            Return Not VersNum1._version.Equals(VersNum2._version)
        End Operator
    
        Public Shared Operator >(VersNum1 As VersionNumber, VersNum2 As VersionNumber) As Boolean
            Return VersNum1._version > VersNum2._version
        End Operator
    
        Public Shared Operator <(VersNum1 As VersionNumber, VersNum2 As VersionNumber) As Boolean
            Return VersNum1._version < VersNum2._version
        End Operator
    
        Public Shared Operator >=(VersNum1 As VersionNumber, VersNum2 As VersionNumber) As Boolean
            Return VersNum1 > VersNum2 OrElse VersNum1.Equals(VersNum2)
        End Operator
    
        Public Shared Operator <=(VersNum1 As VersionNumber, VersNum2 As VersionNumber) As Boolean
            Return VersNum1 < VersNum2 OrElse VersNum1.Equals(VersNum2)
        End Operator
    #End Region
    
    End Class