Strings sometimes have numbers in them. This makes sorting them in VB.NET more challenging. The default sort treats digits as characters and not parts of larger numbers.
A custom solution in VB.NET, called alphanumeric sorting, fixes this problem. It handles groups of digits as entire numbers, not as characters.
Some of the names begin with numbers, and some end with numbers. Often 3 digits like 100 come together—we want 100 to come after 50, not before it.
' ASCII: 100F 50F SR100 SR9 ' Alphanumeric: 50F 100F SR9 SR100
In Main
we create and sort an array of highway names, some of which start with numbers. We then loop over and display those strings after sorting.
IComparer
code, which I named AlphanumComparator
, is more interesting. It provides the Compare method.Integer.Parse
.String
is found to be unequal—either greater or lesser.Imports System.Collections Module Module1 Sub Main() ' The input array. Dim highways() As String = {"100F", "50F", "SR100", "SR9"} ' Sort using the Comparator. Array.Sort(highways, New AlphanumComparator()) ' Loop and display highways. For Each s As String In highways Console.WriteLine(s) Next End Sub End Module ''' <summary> ''' Sorts alphanumerically. ''' </summary> Public Class AlphanumComparator Implements IComparer Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare ' [1] Validate the arguments. Dim s1 As String = x If s1 = Nothing Then Return 0 End If Dim s2 As String = y If s2 = Nothing Then Return 0 End If Dim len1 As Integer = s1.Length Dim len2 As Integer = s2.Length Dim marker1 As Integer = 0 Dim marker2 As Integer = 0 ' [2] Loop over both Strings. While marker1 < len1 And marker2 < len2 ' [3] Get Chars. Dim ch1 As Char = s1(marker1) Dim ch2 As Char = s2(marker2) Dim space1(len1) As Char Dim loc1 As Integer = 0 Dim space2(len2) As Char Dim loc2 As Integer = 0 ' [4] Collect digits for String one. Do space1(loc1) = ch1 loc1 += 1 marker1 += 1 If marker1 < len1 Then ch1 = s1(marker1) Else Exit Do End If Loop While Char.IsDigit(ch1) = Char.IsDigit(space1(0)) ' [5] Collect digits for String two. Do space2(loc2) = ch2 loc2 += 1 marker2 += 1 If marker2 < len2 Then ch2 = s2(marker2) Else Exit Do End If Loop While Char.IsDigit(ch2) = Char.IsDigit(space2(0)) ' [6] Convert to Strings. Dim str1 = New String(space1) Dim str2 = New String(space2) ' [7] Parse Strings into Integers. Dim result As Integer If Char.IsDigit(space1(0)) And Char.IsDigit(space2(0)) Then Dim thisNumericChunk = Integer.Parse(str1) Dim thatNumericChunk = Integer.Parse(str2) result = thisNumericChunk.CompareTo(thatNumericChunk) Else result = str1.CompareTo(str2) End If ' [8] Return result if not equal. If Not result = 0 Then Return result End If End While ' [9] Compare lengths. Return len1 - len2 End Function End Class50F 100F SR9 SR100
The creation of two Strings could be eliminated. We would need to loop over characters one-by-one and compare them. It would also be possible to avoid Integer.Parse
.
AlphanumComparator
as a field or local variable. We do not need to create it more than once.Another option for sorting Strings that include numbers is to first parse those Strings into objects. We could define a Class
that contains the parts of the String
data.
Class
, we could define a Compare method that compares individual parts.In alphanumeric sorting, we must have a way to transform digits into larger numbers. There are many ways to do this—we presented VB.NET code for a general implementation.