【问题标题】:VB6: How to search an array fast?VB6:如何快速搜索数组?
【发布时间】:2015-12-01 16:38:33
【问题描述】:

说,我有一个包含 50000 个元素的字符串数组。对于如此庞大的数组,使用For Next 搜索数组非常慢。有什么快速搜索的方法吗?

注意:使用join & instr 可以在数组中搜索字符串,但是这种方法不好,因为我找不到元素编号

注意:数组未排序。我正在寻找子字符串

【问题讨论】:

  • 数组排序了吗?按照你的标准,什么是慢的?你想达到什么样的性能?
  • 断开连接的记录集可能是最简单和最快的。
  • 您在寻找完全匹配或子字符串吗?
  • 以下是关于断开记录集的一些说明:stackoverflow.com/questions/226978/syncing-two-lists-with-vba
  • UBound(Filter(stringArray, itemToFind)) > -1 会告诉你元素是否在数组中。

标签: vb6


【解决方案1】:

尝试使用 Filter(InputStrings, Value[, Include[, Compare]] ) 函数。它返回一个匹配字符串的数组。

完整的语法可以在MSDN找到

【讨论】:

  • 但它更快吗?顺便说一句,我冒昧地编辑了链接以指向 VB6 文档 而不是 Vb.Net 文档
  • @MarkJ - 不知道,因为我懒得制作一个 50,000 个元素的数组来测试它,尽管内置函数通常是用 C 或 C++ 编写并优化的。我也意识到如果他需要元素的索引,这是不完整的。感谢您修复链接。
  • @MarkJ 你让我好奇,我加载了一个包含随机单词的 50,000 项数组并进行了一些搜索。对于大多数搜索,使用 GetTickCount 函数返回 78 毫秒。不如 Dick Kusleika 的结果,但很快。
【解决方案2】:

这是您使用JoinInStr 的想法的扩展:

Sub TestArraySearch()
Dim A(4) As String
    A(0) = "First"
    A(1) = "Second"
    A(2) = "Third"
    A(3) = "Fourth"
    A(4) = "Fifth"
    Debug.Print FastArraySearch(A, "Fi")
    Debug.Print FastArraySearch(A, "o")
    Debug.Print FastArraySearch(A, "hird")
    Debug.Print FastArraySearch(A, "Fou")
    Debug.Print FastArraySearch(A, "ndTh")
    Debug.Print FastArraySearch(A, "fth")
End Sub

Function FastArraySearch(SearchArray As Variant,SearchPhrase As String) As String
Dim Pos As Long, i As Long, NumCharsProcessed As Long, Txt As String
    Pos = InStr(Join(SearchArray, "§"), SearchPhrase)
    If Pos > 0 Then
        For i = LBound(SearchArray) To UBound(SearchArray)
            NumCharsProcessed = NumCharsProcessed + Len(SearchArray(i)) + 1
            If NumCharsProcessed >= Pos Then
                FastArraySearch = SearchArray(i)
                Exit Function
            End If
        Next i
    End If
End Function

我没有对其进行基准测试,但它应该比每次通过循环进行单独搜索要快。它搜索一次,然后将字符串长度相加,直到找到匹配的位置。因为字符串的长度存储在字符串中的任何字符之前,所以Len函数被高度优化。

如果这种性能仍​​然无法接受,我认为您将需要找到与数组不同的数据结构(例如,如@Remou 建议的那样,断开连接的记录集)。

【讨论】:

  • 是的,这会返回数组索引,但它仍然很慢:(
【解决方案3】:

您能否展示您正在使用的代码需要多长时间?另外,多长才算长?此代码读取 50,000 个字符串,并在 300 多毫秒内找到包含子字符串的 275 个。

Sub testarr()

    Dim vaArr As Variant
    Dim i As Long
    Dim dTime As Double
    Dim lCnt As Long

    dTime = Timer

    vaArr = Sheet1.Range("A1:A50000")

    For i = LBound(vaArr, 1) To UBound(vaArr, 1)
        If InStr(1, vaArr(i, 1), "erez") > 0 Then
            lCnt = lCnt + 1
            Debug.Print i, vaArr(i, 1)
        End If
    Next i

    Debug.Print Timer - dTime
    Debug.Print lCnt

End Sub

【讨论】:

  • +1 表示“多长时间太长?” 300 ms 是否包括 Debug.Print 匹配结果的时间?你能在没有 Debug.Print 的情况下计时并分享结果吗?
  • 好点杰夫克。删除循环中的 Debug.Print,它的头发超过三十 (30) 毫秒。这应该足够快了。
【解决方案4】:

在 VB6 中加快任何数组索引操作的第一种方法是使用以下选项重新编译组件:

  • 单击项目“属性”菜单项
  • 点击“编译”标签
  • 点击“高级优化”按钮
  • 勾选“删除数组边界检查”
  • 按确定等

现在您的数组索引应该与等效的 C/C++ 操作一样快。

唯一的问题是您应该确保您的代码从不引用超出其正常数组范围的索引。以前,您会收到一个 VB 运行时错误。在此之后,您可能会得到访问冲突。

【讨论】:

    【解决方案5】:

    这是一种返回子字符串出现次数的快速方法。希望对您有所帮助!

    Option Explicit
    Option Compare Binary
    Option Base 0
    DefLng A-Z
    Sub TestSubStringOccurence()
    
    Dim GrabRangeArray() As Variant
    Dim i As Long
    Dim L As Long
    Dim RunTime As Double
    Dim SubStringCounter As Long
    Dim J As Long
    Dim InStrPosition As Long
    Dim Ws As Excel.Worksheet
    
    Set Ws = ThisWorkbook.Sheets("Sheet1")
    
    RunTime = Timer
    
    With Ws    
        For i = 1 To 50000
            If i Mod 2 = 0 Then .Cells(i, 1).Value2 = "1 abcdef 2 abcdef 3 abcdef 4 abcdef 5 abcdef" _
            Else .Cells(i, 1).Value2 = i        Next i
    
        GrabRangeArray = .Range("a1:a50000").Value        
    End With    
    RunTime = Timer
    
    'returns number of substring occurrences
    
    For i = 1 To UBound(GrabRangeArray, 1)
        InStrPosition = 1
        Do
            InStrPosition = InStr(InStrPosition, GrabRangeArray(i, 1), "abcdef", vbBinaryCompare)
            If InStrPosition <> 0 Then
                SubStringCounter = SubStringCounter + 1
                InStrPosition = InStrPosition + 6
            End If
        Loop Until InStrPosition = 0
    Next i
    
    Debug.Print "Runtime: " & Timer - RunTime & ", ""abcdef"" occurences: " & SubStringCounter
    End Sub
    

    这是一种快速测试子字符串是否存在的方法,但不返回子字符串出现的次数。

    Option Explicit
    Option Compare Binary
    Option Base 0
    DefLng A-Z
    Sub TestSubStringOccurence()
    Dim GrabRangeArray() As Variant
    Dim I As Long
    Dim L As Long
    Dim RunTime As Double
    Dim SubStringCounter As Long
    Dim J As Long
    Dim InStrPosition As Long
    Dim Ws As Excel.Worksheet
    Const ConstABCDEFString As String = "abcdef"
    Dim B As Boolean
    
    Set Ws = ThisWorkbook.Sheets("Sheet1")
    
    RunTime = Timer
    
    ReDim GrabRangeArray(0 To 49999)
    With Ws
    For I = 1 To 50000
        If I Mod 2 = 0 Then GrabRangeArray(I - 1) = "1 abcdef 2 abcdef 3 abcdef 4 abcdef 5 abcdef" _
        Else GrabRangeArray(I - 1) = I - 1
    Next I
    
    .Range("a1:a50000").Value = Application.Transpose(GrabRangeArray)
    
    End With
    
    RunTime = Timer
    
    For I = 1 To UBound(GrabRangeArray, 1)
        If InStrB(1, GrabRangeArray(I), ConstABCDEFString, vbBinaryCompare) Then _
        SubStringCounter = SubStringCounter + 1
    Next I
    
    Debug.Print "Runtime: " & Timer - RunTime & ", ""abcdef"" occurences: " & SubStringCounter    
    End Sub
    

    【讨论】:

      【解决方案6】:

      好吧,我使用了JoinsSplits,但没有使用任何benchmark

      Function IndexOf(ByRef arr() As String, ByVal str As String) As Integer
          Dim joinedStr As String
          Dim strIndex As Integer
          joinedStr = "|" & Join(arr, "|")
          strIndex = InStr(1, joinedStr, str)
          If strIndex = 0 Then
              IndexOf = -1
              Exit Function
          End If
          joinedStr = Mid(joinedStr, 1, strIndex - 1)
          IndexOf = UBound(Split(joinedStr, "|")) - 1
      End Function
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-21
        • 1970-01-01
        相关资源
        最近更新 更多