【问题标题】:VBA listobject lookup function fastVBA listobject查找功能快速
【发布时间】:2019-05-14 22:40:50
【问题描述】:

我有几张包含 ListObjects 的工作表

当我必须在 listbject 中查找相应的值时,我会执行以下操作:

dim mytable as Listobject
set mytable = thisworkbook.sheets(x).listobject(1)
ValuetoSearch="whatever"
valueResult=""
' looking for the corresponding value of column A in column B
for i=1 to mytable.listrows.count
    if mytable.listcolumns("A").databodyrange.item(i).value=ValuetoSearch then
       valueResult=mytable.listcolumns("B").databodyrange.item(i).value
       exit for
    end if
next i

这行得通。美好的。 但是:

这是最快的搜索方式吗? 当用户选择工作表中的某些单元格(使用工作簿更改选择)时,我正在“即时”使用其中的几个查找操作,并且当“你感觉到”时,这几乎是一秒钟的延迟。对用户来说很烦人。

干杯 谢谢

【问题讨论】:

    标签: excel vba performance lookup-tables listobject


    【解决方案1】:

    VBA 的主要速度下降之一是读取/写入单元格值。您希望尽可能减少读取/写入工作表的次数。事实证明,在大多数情况下,将一系列值读入数组,然后对该数组进行计算,比对值范围本身进行相同的计算要快得多。

    在您的情况下,您可以将表的范围读入一个数组(只有一次读取操作),而不是对每一行进行读取操作。

    Dim mytable As ListObject
    Dim myArr() As Variant
    
    Set mytable = ThisWorkbook.Sheets(x).ListObject(1)
    valuetosearch = "whatever"
    valueResult = ""
    
    myArr = mytable.Range.Value 'Read entire range of values into array
    
    ' looking for the corresponding value of column A in column B
    For i = 1 To mytable.ListRows.Count
        If myArr(i, 1) = valuetosearch Then 'Check the value of the ith row, 1st column
           valueResult = myArr(i,2) 'Get the value of the ith row, 2nd column
           Exit For
        End If
    Next i
    

    我在一个有 1,000,000 行的表上运行了一个快速基准测试,搜索的值只出现在最后一行(最坏的情况)。您的原始代码需要 4.201 秒,而这个需要 0.484 秒。这几乎快 9 倍!

    【讨论】:

    • 这将使它成为@Josh 我最多需要 50 到 100 行。只要低于 0.5 秒,用户就不会感觉到“悬念”。谢谢。干杯。我必须只传递两列。或者如果我传递整个列表对象,可能在时间上并不重要
    • @Tim 的应用匹配解决方案也是我要研究的。
    • 作为脚注和可能的其他读者; Josh 解决方案非常聪明,但请注意以下几点。使用 listObjects 时,通常可以通过名称列访问列。通过这种方式,如果需要,可以随时插入新列,并且不会影响 VBA 代码。如果使用索引引用列,则此方法将不起作用。将数据传递到这样的数组时: myArr = mytable.Range.Value 索引是硬编码的,插入新列会使代码失败。理想情况下,myArr 仅通过名称引用的两个查找列。
    【解决方案2】:

    如果您的数据在工作表上,那么Application.Match() 的速度非常快:

    Sub Tester()
    
        Dim m, rng, t
    
        Set rng = ThisWorkbook.Sheets(1).ListObjects(1).ListColumns(1).DataBodyRange
    
        t = Timer()
        m = Application.Match("Val_1", rng, 0) 'on the first row...
        Debug.Print m, Timer - t 'approx 0 sec
    
        t = Timer()
        m = Application.Match("Val_1000000", rng, 0) 'on the last row...
        Debug.Print m, Timer - t 'approx 0.03 to 0.05 sec
    
    End Sub
    

    m 将是匹配行的索引,或者如果没有匹配则错误 - 您可以使用 IsError(m) 进行测试

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 2018-12-31
      • 1970-01-01
      • 2022-08-03
      相关资源
      最近更新 更多