我正在尝试让MATCH函数像FIND函数一样工作。首先,我生成用于测试的虚拟数据。这是我使用的例程:
Sub Data_Generator()
Randomize
Dim Data(1 To 100000, 1 To 1)
Dim p As Single
For i = 1 To 100000
p = Rnd()
If p < 0.4 Then
Data(i, 1) = "A"
ElseIf p >= 0.4 And p <= 0.7 Then
Data(i, 1) = "B"
Else
Data(i, 1) = "C"
End If
Next i
Range("A1:A100000") = Data
End Sub
现在,我创建一个子例程来查找范围Data
中的字符串 A 。我在这里使用两种使用MATCH函数的方法。第一种方法是重置查找数组的范围,如下面的代码:
Sub Find_Match_1()
T0 = Timer
Dim i As Long, j As Long, k As Long, Data As Range
Dim Output(1 To 100000, 1 To 1)
On Error GoTo Finish
Do
Set Data = Range(Cells(j + 1, 1), "A100000") 'Reset the range of lookup array
i = WorksheetFunction.Match("A", Data, 0)
j = j + i
Output(j, 1) = j 'Label the position of A
k = k + 1 'Counting the number of [A] found
Loop
Finish:
Range("B1:B100000") = Output
InputBox "The number of [A] found are " & k & " in", "Process is complete", Timer - T0
End Sub
对于第二种方法,我通过值vbNullString
指定 A 所在范围的单元格,而不是重置Range("A1:A100000")
。想法是在找到之后删除字符串 A ,并期望MATCH函数在Range("A1:A100000")
中找到下一个字符串 A 。以下是实现第二种方法的代码:
Sub Find_Match_2()
T0 = Timer
Dim n As Long, i As Long, j As Long
Dim Data_Store()
Dim Output(1 To 100000, 1 To 1)
Data_Store = Range("A1:A100000")
On Error GoTo Finish
Do
j = WorksheetFunction.Match("A", Range("A1:A100000"), 0)
Output(j, 1) = j
Cells(j, 1) = vbNullString
n = n + 1
Loop
Finish:
Range("A1:A100000") = Data_Store
Range("B1:B100000") = Output
InputBox "The number of [A] found are " & n & " in", "Process is complete", Timer - T0
End Sub
目标是确定哪种方法在其性能中采用MATCH功能更好。事实证明,第一种方法只完成不到0.4秒,同时第二种方法在我的电脑上完成大约一分钟。所以我的问题是:
答案 0 :(得分:1)
我同意这更像是一个Code Review问题,但我选择考虑自己的好奇心,所以我会分享我发现的内容。
我认为你正在尝试N和N ^ 2计算复杂性的非常经典的案例。看看你看起来非常相似的两种方法,并考虑它们实际上在做什么,记住当你使用Match_type = 0时,MATCH函数可能只是一个线性搜索(因为你的数据是未分类的,而其他的匹配类型可以对已排序的数据进行二进制搜索。)
方法1:
方法2:
很明显,当一种方法不断缩小它搜索的范围时,另一种方法总是从第一个单元开始并搜索整个范围。这将解决一些加速问题,并且已经将方法1提升到一个很好的领先地位,但它几乎不是完整的故事。
真正的关键在于Match必须为每种情况做的工作量。因为它的范围不断缩小并且从列表开始进一步向下移动,无论方法1的匹配从哪个单元开始,它只需要在它到达A之前搜索少量单元并重新开始外循环。同时,方法2不断地摧毁A,使它们越来越不密集,并且在获得任何命中之前强迫自己搜索越来越多的范围。最后,方法2在找到下一个A之前循环通过近100,000个空单元/ B / C。
所以平均而言,方法1的匹配每次只查看几个单元格,而方法2的匹配随着时间的推移越来越长,直到它被迫循环通过整个范围。最重要的是,方法2正在对单元格值进行大量写入,这比您在必须执行数万次时所想的要慢。
老实说,你最好的选择就是自己循环一下细胞,寻找A并随时处理它们。 MATCH没有给表带来任何好处,方法1基本上只是我描述的循环的一个更复杂的版本。
我写下这样的话:
Sub Find_Match_3()
T0 = Timer
Dim k As Long, r As Range
Dim Output(1 To 100000, 1 To 1)
For Each r In Range("A1:A100000").Cells
If r.Value = "A" Then
Output(r.Row, 1) = r.Row 'Label the position of A
k = k + 1 'Counting the number of [A] found
End If
Next
Range("B1:B100000") = Output
InputBox "The number of [A] found are " & k & " in", "Process is complete", Timer - T0
End Sub
我的机器上的速度提高了约30%。