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

106 Views Asked by At

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

1

There are 1 best solutions below

2
On BEST ANSWER

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