Here's the multi-column and single-column QuickSort for VBA, modified from sample code posted by Jim Rech on Usenet.
Notes:
You will notice that I am doing a much more secure encoding than you will see in most code examples on the Internet: this is an Excel forum, and you must anticipate zeros and empty values ββ... Or nested arrays and objects in arrays if your source array comes from (say) a third-party source of market data in real time.
Empty values ββand invalid elements are sent to the end of the list.
Your challenge will be:
QuickSort MyArray ,, 2
... Passing '2' as a column to sort and exclude optional parameters that pass the upper and lower borders of the search domain,
[EDITED] - Fixed an odd formatting failure in <code> tags, which seem to have problems with hyperlinks in code comments.
The clipped hyperlink was an array variant detection in VBA .
Public Sub QuickSortArray(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1, Optional lngColumn As Long = 0) On Error Resume Next 'Sort a 2-Dimensional array ' SampleUsage: sort arrData by the contents of column 3 ' ' QuickSortArray arrData, , , 3 ' 'Posted by Jim Rech 10/20/98 Excel.Programming 'Modifications, Nigel Heffernan: ' ' Escape failed comparison with empty variant ' ' Defensive coding: check inputs Dim i As Long Dim j As Long Dim varMid As Variant Dim arrRowTemp As Variant Dim lngColTemp As Long If IsEmpty(SortArray) Then Exit Sub End If If InStr(TypeName(SortArray), "()") < 1 Then 'IsArray() is somewhat broken: Look for brackets in the type name Exit Sub End If If lngMin = -1 Then lngMin = LBound(SortArray, 1) End If If lngMax = -1 Then lngMax = UBound(SortArray, 1) End If If lngMin >= lngMax Then ' no sorting required Exit Sub End If i = lngMin j = lngMax varMid = Empty varMid = SortArray((lngMin + lngMax) \ 2, lngColumn) ' We send 'Empty' and invalid data items to the end of the list: If IsObject(varMid) Then ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a valid default member or property i = lngMax j = lngMin ElseIf IsEmpty(varMid) Then i = lngMax j = lngMin ElseIf IsNull(varMid) Then i = lngMax j = lngMin ElseIf varMid = "" Then i = lngMax j = lngMin ElseIf VarType(varMid) = vbError Then i = lngMax j = lngMin ElseIf VarType(varMid) > 17 Then i = lngMax j = lngMin End If While i <= j While SortArray(i, lngColumn) < varMid And i < lngMax i = i + 1 Wend While varMid < SortArray(j, lngColumn) And j > lngMin j = j - 1 Wend If i <= j Then ' Swap the rows ReDim arrRowTemp(LBound(SortArray, 2) To UBound(SortArray, 2)) For lngColTemp = LBound(SortArray, 2) To UBound(SortArray, 2) arrRowTemp(lngColTemp) = SortArray(i, lngColTemp) SortArray(i, lngColTemp) = SortArray(j, lngColTemp) SortArray(j, lngColTemp) = arrRowTemp(lngColTemp) Next lngColTemp Erase arrRowTemp i = i + 1 j = j - 1 End If Wend If (lngMin < j) Then Call QuickSortArray(SortArray, lngMin, j, lngColumn) If (i < lngMax) Then Call QuickSortArray(SortArray, i, lngMax, lngColumn) End Sub
... And the version of one column:
Public Sub QuickSortVector(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1) On Error Resume Next 'Sort a 1-Dimensional array ' SampleUsage: sort arrData ' ' QuickSortVector arrData ' ' Originally posted by Jim Rech 10/20/98 Excel.Programming ' Modifications, Nigel Heffernan: ' ' Escape failed comparison with an empty variant in the array ' ' Defensive coding: check inputs Dim i As Long Dim j As Long Dim varMid As Variant Dim varX As Variant If IsEmpty(SortArray) Then Exit Sub End If If InStr(TypeName(SortArray), "()") < 1 Then 'IsArray() is somewhat broken: Look for brackets in the type name Exit Sub End If If lngMin = -1 Then lngMin = LBound(SortArray) End If If lngMax = -1 Then lngMax = UBound(SortArray) End If If lngMin >= lngMax Then ' no sorting required Exit Sub End If i = lngMin j = lngMax varMid = Empty varMid = SortArray((lngMin + lngMax) \ 2) ' We send 'Empty' and invalid data items to the end of the list: If IsObject(varMid) Then ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a default member or property i = lngMax j = lngMin ElseIf IsEmpty(varMid) Then i = lngMax j = lngMin ElseIf IsNull(varMid) Then i = lngMax j = lngMin ElseIf varMid = "" Then i = lngMax j = lngMin ElseIf VarType(varMid) = vbError Then i = lngMax j = lngMin ElseIf VarType(varMid) > 17 Then i = lngMax j = lngMin End If While i <= j While SortArray(i) < varMid And i < lngMax i = i + 1 Wend While varMid < SortArray(j) And j > lngMin j = j - 1 Wend If i <= j Then ' Swap the item varX = SortArray(i) SortArray(i) = SortArray(j) SortArray(j) = varX i = i + 1 j = j - 1 End If Wend If (lngMin < j) Then Call QuickSortVector(SortArray, lngMin, j) If (i < lngMax) Then Call QuickSortVector(SortArray, i, lngMax) End Sub
I used BubbleSort for this kind of thing, but it slows down a lot after the array exceeds 1024 rows. I will add the code below for your reference: note that I did not provide the source code for ArrayDimensions, so it will not be compiled for you unless you reorganize it, or split it into versions of "Array" and "vector".
Public Sub BubbleSort (ByRef InputArray, Optional SortColumn As Integer = 0, Optional Descending As Boolean = False)
'Sort a 1- or 2-Dimensional array.
Dim iFirstRow As Integer
Dim iLastRow As Integer
Dim iFirstCol As Integer
Dim iLastCol As Integer
Dim i As Integer
Dim j as integer
Dim k as integer
Dim varTemp As Variant
Dim OutputArray As Variant
Dim iDimensions As Integer
iDimensions = ArrayDimensions (InputArray)
Select Case iDimensions
Case 1
iFirstRow = LBound (InputArray)
iLastRow = UBound (InputArray)
For i = iFirstRow To iLastRow - 1
For j = i + 1 To iLastRow
If InputArray (i)> InputArray (j) Then
varTemp = InputArray (j)
InputArray (j) = InputArray (i)
InputArray (i) = varTemp
End if
Next j
Next i
Case 2
iFirstRow = LBound (InputArray, 1)
iLastRow = UBound (InputArray, 1)
iFirstCol = LBound (InputArray, 2)
iLastCol = UBound (InputArray, 2)
If SortColumn InputArray (j, SortColumn) Then
For k = iFirstCol To iLastCol
varTemp = InputArray (j, k)
InputArray (j, k) = InputArray (i, k)
InputArray (i, k) = varTemp
Next k
End if
Next j
Next i
End select
If Descending Then
OutputArray = InputArray
For i = LBound (InputArray, 1) To UBound (InputArray, 1)
k = 1 + UBound (InputArray, 1) - i
For j = LBound (InputArray, 2) To UBound (InputArray, 2)
InputArray (i, j) = OutputArray (k, j)
Next j
Next i
Erase OutputArray
End if
End sub
This answer may have been a little late to solve your problem when you need it, but other people will pick it up when they get Google answers for similar problems.