带有循环的 UDF 非常缓慢且效率低下
Posted
技术标签:
【中文标题】带有循环的 UDF 非常缓慢且效率低下【英文标题】:UDF with Loops very slow and inefficient 【发布时间】:2020-05-21 12:53:36 【问题描述】:我有一个代码可以对电子表格中的数千行进行排序,当它在两个不同的列中找到具有特定匹配项的行时,它会在第三列中返回一个值。然而,这个 UDF 被使用了数千次,每次运行数千个循环,它非常慢。有没有办法加快或提高效率?
Dim SearchSheet As Worksheet
Dim PN As Integer
Dim MdlCol As Integer
Dim Mdl As String
Dim Result As Integer
Dim FinalRow As Integer
Dim i As Integer
Application.Volatile True
Select Case True
Case Number < WorksheetFunction.CountA(Sheet2.Range("A:A")) And Model = "1A"
Set SearchSheet = Sheet2
PN = 3
MdlCol = 5
Mdl = "1A"
Result = 30
Case Number < WorksheetFunction.CountA(Sheet2.Range("A:A")) And Model = "1B"
Set SearchSheet = Sheet2
PN = 3
MdlCol = 6
Mdl = "1B"
Result = 30
Case Number < WorksheetFunction.CountA(Sheet2.Range("A:A")) And Model = "1C"
Set SearchSheet = Sheet2
PN = 3
MdlCol = 7
Mdl = "1C"
Result = 30
Case Number >= WorksheetFunction.CountA(Sheet2.Range("A:A")) And Model = "1A"
Set SearchSheet = Sheet3
PN = 2
MdlCol = 18
Mdl = "-1A"
Result = 80
Case Number >= WorksheetFunction.CountA(Sheet2.Range("A:A")) And Model = "1B"
Set SearchSheet = Sheet3
PN = 2
MdlCol = 19
Mdl = "-1B"
Result = 80
Case Number >= WorksheetFunction.CountA(Sheet2.Range("A:A")) And Model = "1C"
Set SearchSheet = Sheet3
PN = 2
MdlCol = 20
Mdl = "-1C"
Result = 80
End Select
FinalRow = WorksheetFunction.CountA(SearchSheet.Range("A:A")) + 10
For i = 2 To FinalRow
If SearchSheet.Cells(i, PN) = PartNumber And SearchSheet.Cells(i, MdlCol) = Mdl Then
If SearchSheet.Cells(i, Result).Value = "X" Then
CalibrationRequired = "Y"
Else
CalibrationRequired = SearchSheet.Cells(i, Result).Value
End If
Exit For
End If
Next i
End Function ```
【问题讨论】:
If SearchSheet.Cells(i, PN) = PartNumber And SearchSheet.Cells(i, MdlCol) = Mdl Then
... 你可以在这里使用WorksheetFunction.CountIfs
。你不需要循环。
我不确定我是否遵循。这会给我匹配标准的出现次数,但是我需要返回该行和特定列(结果)的值。
然后你会做一个lookup on two columns 来实现与CalibrationRequired = SearchSheet.Cells(i, Result).Value
相同的事情。
我从索引匹配开始以引用两个标准,但更糟糕的是,这就是我转向 UDF 的原因。它的计算速度比所有索引匹配数组都快,但仍然很慢。
那么我建议只使用Variant
数组而不是逐个单元格地循环。
【参考方案1】:
我建议:
在开始时放置 LastARow=WorksheetFunction.CountA(SearchSheet.Range("A:A")) 一次,然后重复使用 LastARow,而不是多次重复 COUNTA。
与其循环到最后一行并依次查看每个单元格,不如将所有数据放入一个变体数组并在其上循环
通过从 VBA 启动计算来避免 VBE UDF 减速错误
【讨论】:
完全跑题了,但是你如何达到第三点查尔斯? 1.) 我不遵循第一项。在循环开始之前,作为 CountA 的 FinalRow 已经运行了一次。循环逐行检查两列中的匹配条件。 2.) 我不知道如何将范围变成一个变体数组(假设两列的条件为 2)。或者它是包含整个数据集的 jsut 1 数组,并且事情移动得更快,只是在一个变体数组中? 3.) 什么是 VBE?你是说不要使用用户定义的函数? @Damian fastexcel.wordpress.com/2011/06/13/… @Blake 1. 您的每个 Case 语句都有相同的 COUNTA,因此只需执行一次,如果选择 Sheet3,您只需重做 COUNTA。 2) 使用 Variant Arrays 比逐个单元格处理快几个数量级 3) VBE 是 Visual Basic 编辑器 - VBA UDF 存在一个长期存在的性能错误,每次都会缓慢刷新 VBE 标题栏计算 UDF。如果您有数千次对 UDF 的调用,它将非常缓慢。见fastexcel.wordpress.com/2011/06/13/…以上是关于带有循环的 UDF 非常缓慢且效率低下的主要内容,如果未能解决你的问题,请参考以下文章