Algorithm for Alphanumerical Sort with IComparer
An algorithm for sort alphanumerical strings in their own natural way
Introduction
So I hope I do not have to explain how IComparer
works... just a very quick briefing for those who are not aware.
Most collections and controls of VB.NET give the possibility to define an own control logic. For example, if you want to sort an arraylist that contains other small arrays, you can implement your logic and define that he has to compare the first and the second element of the "jagged" array. Otherwise, if you are a very good coder, but I think you are not going to read this article, you can decide to sort for shades of red some pictures. This is not the case, I would just implement an efficient routine to sort alphanumerically so that the item "WPS-9" is smaller than "WPS-10". This should not be true with the default sorter of .NET.
Using the Code
The controls and classes have a method to implement the Icomparer
:
TreeView1.TreeViewNodeSorter=new TreeSorter 'TreeSorter is the class below
LisView1.ListViewItemSorter ' and others
You have just to build a class that implements that Interface Icompare
(you need just to write Implements IComparer
under the declaration of the class) and this class must implement the method Compare
(you need just to specify after the declaration of the function Implements Icomparer.Compare
).
And here is the algorithm:
Public Class TreeSorter
Implements System.Collections.IComparer
Private obcomparer As New CaseInsensitiveComparer
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer _
Implements System.Collections.IComparer.Compare
Dim tx As TreeNode = CType(x, TreeNode)
Dim ty As TreeNode = CType(y, TreeNode)
Dim nx, ny As New System.Text.StringBuilder
Dim cx(), cy() As Char
cx = tx.Text.ToLower.ToCharArray
cy = ty.Text.ToLower.ToCharArray
If tx.Text.Length = 0 Then Return -1
If ty.Text.Length = 0 Then Return 1
Dim xl, yl, i, j As Integer
xl = UBound(cx)
yl = UBound(cy)
Dim tempX, tempY As Integer
Do
'if finds some number read the whole number
Do While i <= xl AndAlso Char.IsDigit(cx(i))
nx.Append(cx(i))
i += 1
Loop
'the same as above but for the other string
Do While j <= yl AndAlso Char.IsDigit(cy(j))
ny.Append(cy(j))
j += 1
Loop
If nx.Length > 0 Then ' if found some number in the x.text
If ny.Length = 0 Then Return -1 ' but not in the second
'the texts are not balanced therefore we can say that x is smaller than y
tempX = Convert.ToInt32(nx.ToString)
tempY = Convert.ToInt32(ny.ToString)
If tempX > tempY Then Return 1 'confront the numbers
If tempX < tempY Then Return -1
' this code is for the special case some text end with number but the other
'part continue
If i > xl Then
If j > yl Then Return 0
Return -1
End If
If j > yl Then Return 1
'nope both strings are still the same. Reset the counters
nx = New System.Text.StringBuilder
ny = New System.Text.StringBuilder
End If
If ny.Length > 0 Then Return 1 'if found some numbers in the y.text
' and for sure it did not found in the x text as above we can say x is greater than y
'now we can compare the not numeric chars
If cx(i) <> cy(j) Then Return String.Compare(cx(i), cy(j))
If i < xl Then
i += 1
If j < yl Then
j += 1
Else
Return 1 'if comes here means that y is shorter than x
End If
Else
If j < yl Then
Return -1 'vice-versa x is shorter than y
Else
Return 0 'both rows are at the and and there is no greater
End If
End If
Loop
End Function
End Class
Points of Interest
It is fast. It compares the string
s char
by char
, so at the first difference it returns instantly. Enjoy it.