VBA array sort function?

后端 未结 13 2216
北荒
北荒 2020-11-22 05:28

I\'m looking for a decent sort implementation for arrays in VBA. A Quicksort would be preferred. Or any other sort algorithm other than bubble or merge would suffice.

<
13条回答
  •  暗喜
    暗喜 (楼主)
    2020-11-22 06:02

    I posted some code in answer to a related question on StackOverflow:

    Sorting a multidimensionnal array in VBA

    The code samples in that thread include:

    1. A vector array Quicksort;
    2. A multi-column array QuickSort;
    3. A BubbleSort.

    Alain's optimised Quicksort is very shiny: I just did a basic split-and-recurse, but the code sample above has a 'gating' function that cuts down on redundant comparisons of duplicated values. On the other hand, I code for Excel, and there's a bit more in the way of defensive coding - be warned, you'll need it if your array contains the pernicious 'Empty()' variant, which will break your While... Wend comparison operators and trap your code in an infinite loop.

    Note that quicksort algorthms - and any recursive algorithm - can fill the stack and crash Excel. If your array has fewer than 1024 members, I'd use a rudimentary BubbleSort.

    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
    ' Sample Usage: 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

提交回复
热议问题