在 VBA 中对多维数组进行排序 [英] Sorting a multidimensionnal array in VBA

查看:146
本文介绍了在 VBA 中对多维数组进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已将以下数组 Dim myArray(10,5) 定义为 Long 并希望对其进行排序.这样做的最佳方法是什么?

我需要处理大量数据,例如 1000 x 5 矩阵.主要包含数字和日期,需要按照某一列进行排序

解决方案

这是 VBA 的多列和单列 QuickSort,修改自 Jim Rech 在 Usenet 上发布的代码示例.

注意事项:

您会注意到,与您在网络上的大多数代码示例中看到的相比,我进行了很多的防御性编码:这是一个 Excel 论坛,您可以预测空值和空值...或者嵌套数组和数组中的对象,如果您的源数组来自(例如)第三方实时市场数据源.

空值和无效项被发送到列表的末尾.

要对多列数组进行排序,您的调用将是:

 QuickSortArray MyArray,,,2
...传递 '2' 作为要排序的列并排除传递上层的可选参数和搜索域的下限.

对单列数组(向量)进行排序,改为使用:

QuickSortVector Myarray

这里也排除了可选参数.

[已编辑] - 修复了 <code> 中一个奇怪的格式错误;标签,代码注释中的超链接似乎有问题.

我切除的超链接是检测 VBA 中的数组变体.

Public Sub QuickSortArray(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1, Optional lngColumn As Long = 0)出错时继续下一步'对二维数组进行排序' SampleUsage:按第 3 列的内容对 arrData 进行排序'' QuickSortArray arrData, , , 3''由 Jim Rech 于 98 年 10 月 20 日发布.'修改,奈杰尔·赫弗南:' ' 转义失败与空变体的比较' ' 防御性编码:检查输入昏暗的我Dim j As LongDim varMid 作为变体Dim arrRowTemp 作为变体Dim lngColTemp 尽可能长如果 IsEmpty(SortArray) 那么退出子万一如果 InStr(TypeName(SortArray), "()") <1 然后 'IsArray() 有点坏:在类型名称中查找括号退出子万一如果 lngMin = -1 那么lngMin = LBound(SortArray, 1)万一如果 lngMax = -1 那么lngMax = UBound(SortArray, 1)万一If lngMin >= lngMax Then ' 不需要排序退出子万一i = lngMinj = lngMaxvarMid = 空varMid = SortArray((lngMin + lngMax) \ 2, lngColumn)' 我们将 'Empty' 和无效的数据项发送到列表的末尾:If IsObject(varMid) Then ' 注意我们不检查 isObject(SortArray(n)) - varMid *可能* 选择一个有效的默认成员或属性i = lngMaxj = lngMinElseIf IsEmpty(varMid) 然后i = lngMaxj = lngMinElseIf IsNull(varMid) 然后i = lngMaxj = lngMinElseIf varMid = "";然后i = lngMaxj = lngMinElseIf VarType(varMid) = vbError Theni = lngMaxj = lngMinElseIf VarType(varMid) >17 那么i = lngMaxj = lngMin万一当 i <= j虽然 SortArray(i, lngColumn) 明明j = j - 1温德如果 i <= j 那么'交换行ReDim arrRowTemp(LBound(SortArray, 2) 到 UBound(SortArray, 2))对于 lngColTemp = LBound(SortArray, 2) 到 UBound(SortArray, 2)arrRowTemp(lngColTemp) = SortArray(i, lngColTemp)SortArray(i, lngColTemp) = SortArray(j, lngColTemp)SortArray(j, lngColTemp) = arrRowTemp(lngColTemp)下一个 lngColTemp擦除 arrRowTemp我 = 我 + 1j = j - 1万一温德如果 (lngMin 

...以及单列数组版本:

公共子QuickSortVector(ByRef SortArray As Variant,可选lngMin As Long = -1,可选lngMax As Long = -1)出错时继续下一步'对一维数组进行排序' SampleUsage: 排序 arrData'' QuickSortVector arrData'' 最初由 Jim Rech 于 98 年 10 月 20 日发表 Excel.Programming' 修改,奈杰尔·赫弗南:' ' 与数组中的空变体进行比较时转义失败' ' 防御性编码:检查输入昏暗的我Dim j As LongDim varMid 作为变体Dim varX 作为变体如果 IsEmpty(SortArray) 那么退出子万一如果 InStr(TypeName(SortArray), "()") <1 然后 'IsArray() 有点坏:在类型名称中查找括号退出子万一如果 lngMin = -1 那么lngMin = LBound(SortArray)万一如果 lngMax = -1 那么lngMax = UBound(SortArray)万一If lngMin >= lngMax Then ' 不需要排序退出子万一i = lngMinj = lngMaxvarMid = 空varMid = SortArray((lngMin + lngMax) \ 2)' 我们将 'Empty' 和无效的数据项发送到列表的末尾:If IsObject(varMid) Then ' 请注意,我们不检查 isObject(SortArray(n)) - varMid *可能* 选择默认成员或属性i = lngMaxj = lngMinElseIf IsEmpty(varMid) 然后i = lngMaxj = lngMinElseIf IsNull(varMid) 然后i = lngMaxj = lngMinElseIf varMid = "";然后i = lngMaxj = lngMinElseIf VarType(varMid) = vbError Theni = lngMaxj = lngMinElseIf VarType(varMid) >17 那么i = lngMaxj = lngMin万一当 i <= j虽然 SortArray(i) 明明j = j - 1温德如果 i <= j 那么' 交换项目varX = SortArray(i)SortArray(i) = SortArray(j)SortArray(j) = varX我 = 我 + 1j = j - 1万一温德如果 (lngMin 

我曾经将 BubbleSort 用于这种事情,但在数组超过 1024 行后,它会严重变慢.我提供了以下代码供您参考:请注意,我没有提供 ArrayDimensions 的源代码,因此除非您对其进行重构或将其拆分为Array"和vector"版本,否则它不会为您编译.<前>Public Sub BubbleSort(ByRef InputArray, Optional SortColumn As Integer = 0, Optional Descending As Boolean = False)' 对一维或二维数组进行排序.将 iFirstRow 调暗为整数将 iLastRow 调暗为整数将 iFirstCol 调暗为整数将 iLastCol 调暗为整数Dim i 作为整数将 j 调暗为整数将 k 调暗为整数Dim varTemp 作为变体Dim OutputArray 作为变体将 iDimensions 调暗为整数iDimensions = ArrayDimensions(InputArray)选择案例 iDimensions情况1iFirstRow = LBound(InputArray)iLastRow = UBound(InputArray)对于 i = iFirstRow 到 iLastRow - 1对于 j = i + 1 到 iLastRow如果 InputArray(i) > InputArray(j) 那么varTemp = InputArray(j)输入数组(j) = 输入数组(i)InputArray(i) = varTemp万一下一个接下来我案例二iFirstRow = LBound(InputArray, 1)iLastRow = UBound(InputArray, 1)iFirstCol = LBound(InputArray, 2)iLastCol = UBound(InputArray, 2)如果 SortColumn InputArray(j, SortColumn) 那么对于 k = iFirstCol 到 iLastColvarTemp = InputArray(j, k)InputArray(j, k) = InputArray(i, k)InputArray(i, k) = varTemp下一个万一下一个接下来我结束选择如果下降 那么输出数组 = 输入数组对于 i = LBound(InputArray, 1) 到 UBound(InputArray, 1)k = 1 + UBound(InputArray, 1) - i对于 j = LBound(InputArray, 2) 到 UBound(InputArray, 2)InputArray(i, j) = OutputArray(k, j)下一个接下来我擦除输出数组万一结束子

这个答案可能在您需要时解决您的问题来得有点晚,但其他人在 Google 搜索类似问题的答案时会选择它.

I have defined the following Array Dim myArray(10,5) as Long and would like to sort it. What would be the best method to do that?

I will need to handle a lot of data like a 1000 x 5 Matrix. It contains mainly numbers and dates and need to sort it according to a certain column

解决方案

Here's a multi-column and a single-column QuickSort for VBA, modified from a code sample posted by Jim Rech on Usenet.

Notes:

You'll notice that I do a lot more defensive coding than you'll see in most of the code samples out there on the web: this is an Excel forum, and you've got to anticipate nulls and empty values... Or nested arrays and objects in arrays if your source array comes from (say) a third-party realtime market data source.

Empty values and invalid items are sent to the end of the list.

To sort multi-column arrays, your call will be:

 QuickSortArray MyArray,,,2
...Passing '2' as the column to sort on and excluding the optional parameters that pass the upper and lower bounds of the search domain.

Sorting single-column arrays (vectors), instead use:

QuickSortVector Myarray

Here too excluding the optional parameters.

[EDITED] - fixed an odd formatting glitch in the <code> tags, which seem to have a problem with hyperlinks in code comments.

The Hyperlink I excised was Detecting an Array Variant 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 single-column array version:

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 to use BubbleSort for this kind of thing, but it slows down, severely, after the array exceeds 1024 rows. I include the code below for your reference: please note that I haven't provided source code for ArrayDimensions, so this will not compile for you unless you refactor it - or split it out into 'Array' and 'vector' versions.

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 arrived a bit late to solve your problem when you needed to, but other people will pick it up when they Google for answers for similar problems.

这篇关于在 VBA 中对多维数组进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆