带有循环的 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 非常缓慢且效率低下的主要内容,如果未能解决你的问题,请参考以下文章

获取具有特定数量的重复值的行

Pandas Dataframe 循环遍历列效率低下

尽管 Python 简单,但循环效率低下

ConcurrentHashMap 源码浅析 1.7

加载视图控制器后如何加载 UIImageView

疑难杂症02ResultSet.next() 效率低下问题解决