Arrays VBA排序二维数组(按字母顺序排列的文本值)-优化

Arrays VBA排序二维数组(按字母顺序排列的文本值)-优化,arrays,excel,vba,sorting,Arrays,Excel,Vba,Sorting,要接收包含Excel中按字母顺序排序的数据的数组,我总是使用以下方法: With ThisWorkbook.Worksheets("data") LastRow = .Cells.Find(what:="*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row .Range("a2:b" & LastRow).Sort key1:=.Range("a1"), order1:=xlAscending vD

要接收包含Excel中按字母顺序排序的数据的数组,我总是使用以下方法:

With ThisWorkbook.Worksheets("data")
    LastRow = .Cells.Find(what:="*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
    .Range("a2:b" & LastRow).Sort key1:=.Range("a1"), order1:=xlAscending
    vData = .Range("a2:b" & LastRow)
End With
我最多可以有3个排序条件,如果我使用不同的排序参数多次运行排序,则这是一个无限数

问题是这需要时间。最糟糕的情况是,当我收到一个数组作为代码内操作的结果时,我必须首先将数组粘贴到工作表中,然后进行排序。有几十万行,需要几秒钟

我使用我对快速排序算法的修改对数字进行排序,但我认为按字母顺序对文本进行排序需要“StrComp”,根据我的经验,这相对比较耗时


您是否见过或认为有可能创建一个VBA二维数组字母排序算法(甚至可以是一个标准列),该算法的执行速度将快于
Range.Sort
(或粘贴大数组+排序)?如果是,将如何比较字符串?

您可以尝试使用
ADODB
库中的方法,只需对数据执行
SELECT
查询,其中
按数据中的文本列排序,无需编写自定义排序函数

使用这种方法将允许您扩展到任意数量的文本列,而无需担心自定义函数将如何处理多个文本数据列

样本数据和输出:

上述示例代码-请按照注释进行操作

Option Explicit

Sub SortDataBy2TextColumnsWithADO()

    Dim rngInput As Range
    Dim rngOutput As Range
    Dim strWbName As String
    Dim strConnection As String
    Dim objConnection As ADODB.Connection
    Dim strRangeReference As String
    Dim strSql As String
    Dim objRecordSet As ADODB.Recordset
    Dim varSortedData As Variant
    Dim wsf As WorksheetFunction

    ' set input range - includes header
    Set rngInput = ThisWorkbook.Worksheets("Sheet1").Range("A1:C19")

    ' set output range - just the first cell
    Set rngOutput = ThisWorkbook.Worksheets("Sheet1").Range("E1")

    ' copy the headers over
    rngOutput.Resize(1, 3).Value = rngInput.Rows(1).Value

    ' connection string for ACE OLEDB provider
    strWbName = ThisWorkbook.FullName
    strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
        "Data Source=" & strWbName & ";" & _
        "Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"

    ' make the connection to current workbook (better saved the workbook first)
    Set objConnection = New ADODB.Connection
    objConnection.Open strConnection

    ' get range reference as a string suitable for sql query
    strRangeReference = "[" & rngInput.Parent.Name & "$" & rngInput.Address(False, False) & "]"
    ' get the data ordered by text columns (1 and 2) and values (3)
    strSql = "select * from " & strRangeReference & " order by 1, 2, 3"

    ' populate the recordset
    Set objRecordSet = New ADODB.Recordset
    objRecordSet.Open strSql, objConnection

    ' get the sorted data to the variant
    varSortedData = objRecordSet.GetRows

    ' need to transpose the sorted data
    varSortedData = WorksheetFunction.Transpose(varSortedData)

    ' output the transposed sorted data to target range
    rngOutput.Offset(1, 0).Resize(UBound(varSortedData, 1), UBound(varSortedData, 2)).Value = varSortedData

    ' clean up
    objRecordSet.Close
    Set objRecordSet = Nothing
    objConnection.Close
    Set objConnection = Nothing

End Sub
注意以下几点:

  • 我在一个未保存的工作簿上出错-因此可能比您至少保存一次工作簿要好
  • 排序后的数据需要根据输出范围进行转置-请参阅和

您可以尝试使用
ADODB
库中的方法,只需对数据执行
SELECT
查询,即可
按数据中的文本列排序,无需编写自定义排序函数

使用这种方法将允许您扩展到任意数量的文本列,而无需担心自定义函数将如何处理多个文本数据列

样本数据和输出:

上述示例代码-请按照注释进行操作

Option Explicit

Sub SortDataBy2TextColumnsWithADO()

    Dim rngInput As Range
    Dim rngOutput As Range
    Dim strWbName As String
    Dim strConnection As String
    Dim objConnection As ADODB.Connection
    Dim strRangeReference As String
    Dim strSql As String
    Dim objRecordSet As ADODB.Recordset
    Dim varSortedData As Variant
    Dim wsf As WorksheetFunction

    ' set input range - includes header
    Set rngInput = ThisWorkbook.Worksheets("Sheet1").Range("A1:C19")

    ' set output range - just the first cell
    Set rngOutput = ThisWorkbook.Worksheets("Sheet1").Range("E1")

    ' copy the headers over
    rngOutput.Resize(1, 3).Value = rngInput.Rows(1).Value

    ' connection string for ACE OLEDB provider
    strWbName = ThisWorkbook.FullName
    strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
        "Data Source=" & strWbName & ";" & _
        "Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"

    ' make the connection to current workbook (better saved the workbook first)
    Set objConnection = New ADODB.Connection
    objConnection.Open strConnection

    ' get range reference as a string suitable for sql query
    strRangeReference = "[" & rngInput.Parent.Name & "$" & rngInput.Address(False, False) & "]"
    ' get the data ordered by text columns (1 and 2) and values (3)
    strSql = "select * from " & strRangeReference & " order by 1, 2, 3"

    ' populate the recordset
    Set objRecordSet = New ADODB.Recordset
    objRecordSet.Open strSql, objConnection

    ' get the sorted data to the variant
    varSortedData = objRecordSet.GetRows

    ' need to transpose the sorted data
    varSortedData = WorksheetFunction.Transpose(varSortedData)

    ' output the transposed sorted data to target range
    rngOutput.Offset(1, 0).Resize(UBound(varSortedData, 1), UBound(varSortedData, 2)).Value = varSortedData

    ' clean up
    objRecordSet.Close
    Set objRecordSet = Nothing
    objConnection.Close
    Set objConnection = Nothing

End Sub
注意以下几点:

  • 我在一个未保存的工作簿上出错-因此可能比您至少保存一次工作簿要好
  • 排序后的数据需要根据输出范围进行转置-请参阅和

您可能会发现此链接很有帮助。您可能会发现此链接很有帮助。实际上,在运行了更多的测试之后,我有两个问题。首先,当我对数据集进行排序(第7列升序,第1列降序)时,使用此解决方案,我可以在3,15秒内处理50000行。使用标准Excel排序,我可以在3,15秒内对310 000行进行排序(复制原始数据集的粘贴重复)。第二个问题是存在65536行限制,超过该限制后,会出现一个错误:“Microsoft Access数据库引擎无法找到对象…”我找到了解决第二个问题的方法,方法是从SQL查询字符串中删除工作表名称引用:`&rngInput.Parent.name&“$”&“,但在310000行上,这是18秒!我猜答案是代码优化,而不是性能优化-即解决方案将始终在任意输入数据集上运行,而无需修改算法,并且可能比任何自定义排序算法更简洁。实际上,在运行更多测试后,我有两个问题。首先,当我对数据集进行排序(第7列升序,第1列降序)时,使用此解决方案,我可以在3,15秒内处理50000行。使用标准Excel排序,我可以在3,15秒内对310 000行进行排序(复制原始数据集的粘贴重复)。第二个问题是存在65536行限制,超过该限制后,会出现一个错误:“Microsoft Access数据库引擎无法找到对象…”我找到了解决第二个问题的方法,方法是从SQL查询字符串中删除工作表名称引用:`&rngInput.Parent.name&“$”&“,但在310000行上,这是18秒!我猜答案是代码优化,而不是性能优化,即解决方案将始终在任意输入数据集上运行,而无需修改算法,并且可能比任何自定义排序算法更简洁。