arrays - VBA - 匹配2个排序字符串数组,其中某些元素不匹配 - 优化

标签 arrays excel vba algorithm sorting

我有 2 个数据集,其中有很多字符串,我需要对其进行匹配。第一个是 1200 行,第二个大约 800 000 行。我通过 VBA 调用的 Excel 排序对这两个集合进行排序,以便它们按升序排列,因此我可以通过在最后一行后开始第二个数据集的每个下一个迭代来显着优化搜索速度匹配。

不幸的是,当没有找到匹配项时,Exit For永远不会遇到,即使根据我的搜索词检查的字符串在字母表中更靠前(>我的字符串)。我尝试实现比较 If vData1(arrayIndex1, 1) < vData2(arrayIndex2, 1) Then (也许之前使用“Mod”检查,如果在每次迭代中执行都会很慢),但我遇到不正确的比较值,例如 ?"µm">"zzzzz"返回 true,而在数据集中,它应该是在以“a”开头的字符串之前。

有没有可靠的方法来解决这个问题?

Dim optimizedCounter as long, arrayIndex1 as long, arrayIndex2 as long
Dim vData1 as variant, vData2 as variant

'sort 2 data sets in Excel ascending
'assign data sets to arrays vData1 and vData2

optimizedCounter = LBound(vData2)

For arrayIndex1 = LBound(vData1) To UBound(vData1)
    For arrayIndex2 = optimizedCounter To UBound(vData2)
        If vData1(arrayIndex1, 1) = vData2(arrayIndex2, 1) Then
            'do action when strings match
            optimizedCounter = arrayIndex2 'narrow down 2nd data set's list, arrayIndex2 + 1 if vData1 has no duplicates
            Exit For 'match has been found, exit loop and continue matching for next element in 1st data set
        End If
    Next arrayIndex2
Next arrayIndex1

编辑:

感谢大家提出的精彩建议。目前 A.S.H 的解决方案为 Application.Evaluate/StrComp为我成功了。因为我使用默认的二进制比较 vData1(arrayIndex1, 1) = vData2(arrayIndex2, 1) ,如果我想保留当前速度,则无法使用选项比较文本。

For arrayIndex1 = LBound(vData1) To UBound(vData1)
    For arrayIndex2 = optimizedCounter To UBound(vData2)
        If vData1(arrayIndex1, 1) = vData2(arrayIndex2, 1) Then
            'do action when strings match
            optimizedCounter = arrayIndex2 'narrow down 2nd data set's list, arrayIndex2 + 1 if vData1 has no duplicates
            Exit For 'match has been found, exit loop and continue matching for next element in 1st data set
        ElseIf arrayIndex2 Mod 1000 = 0 Then
            If Application.Evaluate("""" & vData2(arrayIndex2, 1) & _
            """ > """ & vData1(arrayIndex1, 1) & """") Then Exit For
            'line below can be used instead of Application.Evaluate, the same speed, easier structure
            'If StrComp(vData2(arrayIndex2, 1), vData1(arrayIndex1, 1), vbTextCompare) = 1 Then Exit For
        End If           
    Next arrayIndex2
Next arrayIndex1 

由于此方法需要一些时间,因此我被迫每 n 次迭代就使用它,以获得性能增益。根据数据集长度和匹配值的百分比,最佳 mod 值会有所不同。

作为对检查的组合数量的评论,我的搜索词列表包含重复项。

原版代码:

执行时间:12.76

处理的组合:144596591

Application.Evaluate 或 StrComp:

执行时间:17.30

处理的组合:1192341

条件 mod 50 = 0 下的 Application.Evaluate 或 StrComp:

执行时间:0.48

处理的组合:1201717

条件 mod 1000 = 0 下的 Application.Evaluate 或 StrComp:

执行时间:0.16

处理的组合:1376317

由于处理的组合数量较多,因此增加 mod 值将增加执行时间。

我尝试输入 With Application在主循环之外并使用.Evaluate,它对速度完全没有影响。

编辑2:

Application.MatchApplication.Vlookup不适用于行数 > 65536 的数组。然而,正如评论指出的那样,它们确实适用于范围。

Dim vMatch as Variant, myRng as Range

'myRng is set to one-column range of values to look for, about 800K rows

For arrayIndex1 = LBound(vData1) To UBound(vData1)
        vMatch = Application.Match(vData1(arrayIndex1, 1), myRng, 0)
        If Not IsError(vMatch) Then
            'do action when strings match
        End If
Next arrayIndex1

Application.Match 且 MatchType = 0:

执行时间:28.81

查找次数:1200

最佳答案

If vData1(arrayIndex1, 1) < vData2(arrayIndex2, 1) Then ... I encounter incorrect comparison values, for example ?"µm">"zzzzz" returns true, while in data set it is as it should be, before strings starting with "a".

事实上,如果之前的排序和你的代码中的字符串比较操作不同,那么之前的排序就变得毫无用处。发生这种情况是因为

VBA 中的比较默认为二进制

?"µm">"zzzzz"                              --->   True
?Application.Evaluate("""µm"">""zzzzz""")  --->   False
?StrComp("µm", "zzzzz")                    --->    1 
?StrComp("µm", "zzzzz", vbTextCompare)     --->   -1 
                        ^^^^^^^^^^^^^^

附:除非你设置Option Compare TextstrComp正如评论中指出的,或者通过使用 Excel 的比较:

If Application.Evaluate("""" & vData1(arrayIndex1, 1) & _ 
    """ < """ & vData2(arrayIndex2, 1) & """") Then

这将解决比较不匹配的问题。确实根据 < 停止循环比较应该使它更快。这是否是最好的算法是另一个争论。您的数组正在排序,二分搜索应该是一个完美的候选者。

除非您使用二分搜索,否则请考虑使用 Excel 的内置函数,即 Application.VLookupApplication.Match ,它们几乎比 VBA 循环快一个数量级,即使后者正在预取数组上工作。

关于arrays - VBA - 匹配2个排序字符串数组,其中某些元素不匹配 - 优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43552170/

相关文章:

image - 使用VBA将Excel文件中的图片导出为jpg

php - 通过发布的数组过滤数据?

javascript - 具有多种类型的内联解析数组

arrays - 将满足条件的数组值复制到另一列excel vba

vba - 如何创建 Double 的空数组

excel - VBScript 打开 Excel 文件,然后执行另存为

ios - 无法将类型 '[String]' 的值分配给类型 'String?' (Swift)

arrays - Base64编码的字符串到二进制文件

excel - 如何使用 Excel VBA 在单次运行中用一列中的 5 个文字和另一列中的 5 个公式填充 5 x 2 范围

Excel:与日期结果连接时附加了一个数字而不是日期