2 dimensional array quick sort is slow

Hafi

New Member
Joined
Jan 26, 2023
Messages
2
Office Version
  1. 2021
Platform
  1. Windows
Hi,

I'm trying to create a flexible version of the recursive quick sort model where you can send the following input to the function:
'arrInput: array to sort
'sortKey: row or column to sort on
'sortOrder: xlAscending or xlDescending
'sortOrientation: xlSortRows or xlSortColumns
'header: True or False
'lngMin (optional): start row/column if sorting part of array
'lngMax (optional): end row/column if sorting part of array

The code is working fine but is very slow when the input array contains more than just a few lines of data. Already at 10 000 rows and 3 columns it takes about 4 seconds to sort the array and if I use an array with 1 000 000 rows Excel crashes. Adding one more columns to the array is not an big problem, it looks like it's the number of rows (if sorting on rows) that's the problem. I guess that the number of iterations grow exponentially when adding more rows?

Is there a way to improve the code below to make the quick sort better and faster?

VBA Code:
Sub testSort()

Dim arr As Variant
arr = Range("A1:C10000") 'Range contains random numbers 1 - 1 000 000

t = Timer
arr = SortArrayQuick(arr, 2, xlAscending, xlSortRows, False)
Range("K1").Resize(UBound(arr), UBound(arr, 2)) = arr
MsgBox Timer - t

'Result: 4,086 seconds

End Sub


Public Function SortArrayQuick(ByRef arrInput As Variant, sortKey As Long, sortOrder As XlSortOrder, sortOrientation As XlSortOrientation, header As Boolean, Optional lngMin As Long = -1, Optional lngMax As Long = -1) As Variant

'arrInput: array to sort
'sortKey: row or column to sort on
'sortOrder: xlAscending or xlDescending
'sortOrientation: xlSortRows or xlSortColumns
'header: True or False
'lngMin (optional): start row/column if sorting part of array
'lngMax (optional): end row/column if sorting part of array


    Dim i As Long
    Dim j As Long
    Dim varMid As Variant
    Dim arrTemp As Variant
    Dim RowOrColTemp As Long

     
    If IsEmpty(arrInput) Then
        Exit Function
    End If
    If InStr(TypeName(arrInput), "()") < 1 Then
        Exit Function
    End If
    
    If lngMin = -1 Then
        If sortOrientation = xlSortRows Then
            lngMin = LBound(arrInput, 1)
        Else
            lngMin = LBound(arrInput, 2)
        End If
    End If
    
    If header = True Then
        lngMin = lngMin + 1
    End If
    
    If lngMax = -1 Then
        If sortOrientation = xlSortRows Then
            lngMax = UBound(arrInput, 1)
        Else
            lngMax = UBound(arrInput, 2)
        End If
    End If
    
    If lngMin >= lngMax Then
        Exit Function
    End If

    i = lngMin
    j = lngMax

    varMid = Empty
    If sortOrientation = xlSortRows Then
        varMid = arrInput((lngMin + lngMax) \ 2, sortKey)
    Else
        varMid = arrInput(sortKey, (lngMin + lngMax) \ 2)
    End If
       
    
    If IsObject(varMid) Then
        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
        If sortOrder = xlAscending Then
            If sortOrientation = xlSortRows Then
                While arrInput(i, sortKey) < varMid And i < lngMax
                    i = i + 1
                Wend
                While varMid < arrInput(j, sortKey) And j > lngMin
                    j = j - 1
                Wend
            Else
                While arrInput(sortKey, i) < varMid And i < lngMax
                    i = i + 1
                Wend
                While varMid < arrInput(sortKey, j) And j > lngMin
                    j = j - 1
                Wend
            End If
        Else
            If sortOrientation = xlSortRows Then
                While arrInput(i, sortKey) > varMid And i < lngMax
                    i = i + 1
                Wend
                While varMid > arrInput(j, sortKey) And j > lngMin
                    j = j - 1
                Wend
            Else
                While arrInput(sortKey, i) > varMid And i < lngMax
                    i = i + 1
                Wend
                While varMid > arrInput(sortKey, j) And j > lngMin
                    j = j - 1
                Wend
            End If
        End If
        

        If i <= j Then
            If sortOrientation = xlSortRows Then
                ReDim arrTemp(LBound(arrInput, 2) To UBound(arrInput, 2))
                For RowOrColTemp = LBound(arrInput, 2) To UBound(arrInput, 2)
                    arrTemp(RowOrColTemp) = arrInput(i, RowOrColTemp)
                    arrInput(i, RowOrColTemp) = arrInput(j, RowOrColTemp)
                    arrInput(j, RowOrColTemp) = arrTemp(RowOrColTemp)
                Next RowOrColTemp
            Else
                ReDim arrTemp(LBound(arrInput, 1) To UBound(arrInput, 1))
                For RowOrColTemp = LBound(arrInput, 1) To UBound(arrInput, 1)
                    arrTemp(RowOrColTemp) = arrInput(RowOrColTemp, i)
                    arrInput(RowOrColTemp, i) = arrInput(RowOrColTemp, j)
                    arrInput(RowOrColTemp, j) = arrTemp(RowOrColTemp)
                Next RowOrColTemp
            End If
                
            Erase arrTemp
            i = i + 1
            j = j - 1
            
        End If
    Wend
    
    header = False
    
    If (lngMin < j) Then arrInput = SortArrayQuick(arrInput, sortKey, sortOrder, sortOrientation, header, lngMin, j)
    If (i < lngMax) Then arrInput = SortArrayQuick(arrInput, sortKey, sortOrder, sortOrientation, header, i, lngMax)

    SortArrayQuick = arrInput
    
End Function
 

Excel Facts

How to fill five years of quarters?
Type 1Q-2023 in a cell. Grab the fill handle and drag down or right. After 4Q-2023, Excel will jump to 1Q-2024. Dash can be any character.

Forum statistics

Threads
1,223,893
Messages
6,175,239
Members
452,621
Latest member
Laura_PinksBTHFT

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top