如何针对高搜索次数优化vlookup?(VLOOKUP的替代品)

d-s*_*yer 23 performance vba dictionary excel-vba vlookup

我正在寻找vlookup的替代品,在感兴趣的环境中提高性能.

上下文如下:

  • 我有一个{key; data}数据集很大(约100'000条记录)
  • 我想对数据集执行大量的VLOOKUP操作(典型的用途是重新排序整个数据集)
  • 我的数据集没有重复的密钥
  • 我只寻找完全匹配(最后一个参数VLOOKUPFALSE)

一个架构来解释:

参考表:( "sheet1")

        A           B
     1
     2  key1        data1
     3  key2        data2
     4  key3        data3
   ...  ...         ...
 99999  key99998    data99998
100000  key99999    data99999
100001  key100000   data100000
100002
Run Code Online (Sandbox Code Playgroud)

查找表:

        A           B
     1
     2  key51359    =VLOOKUP(A2;sheet1!$A$2:$B$100001;2;FALSE)
     3  key41232    =VLOOKUP(A3;sheet1!$A$2:$B$100001;2;FALSE)
     4  key10102    =VLOOKUP(A3;sheet1!$A$2:$B$100001;2;FALSE)
   ...  ...         ...
 99999  key4153     =VLOOKUP(A99999;sheet1!$A$2:$B$100001;2;FALSE)
100000  key12818    =VLOOKUP(A100000;sheet1!$A$2:$B$100001;2;FALSE)
100001  key35032    =VLOOKUP(A100001;sheet1!$A$2:$B$100001;2;FALSE)
100002
Run Code Online (Sandbox Code Playgroud)

在我的Core i7 M 620 @ 2.67 GHz上,计算时间约为10分钟

在这种情况下,VLOOKUP是否有更好的性能?

d-s*_*yer 22

我考虑了以下替代方案:

  • VLOOKUP数组公式
  • 匹配/索引
  • VBA(使用字典)

比较的表现是:

  • VLOOKUP简单公式:~10分钟
  • VLOOKUP数组公式:~10分钟(1:1性能指标)
  • MATCH/INDEX:约2分钟(5:1表现指数)
  • VBA(使用字典):~6秒(100:1性能指标)

使用相同的参考表

1)查找表:( vlookup数组公式版)

         A          B
     1
     2   key51359    {=VLOOKUP(A2:A10001;sheet1!$A$2:$B$100001;2;FALSE)}
     3   key41232    formula in B2
     4   key10102    ... extends to
   ...   ...         ... 
 99999   key4153     ... cell B100001
100000   key12818    ... (select whole range, and press
100001   key35032    ... CTRL+SHIFT+ENTER to make it an array formula)
100002
Run Code Online (Sandbox Code Playgroud)

2)查找表:(匹配+索引版)

         A           B                                       C
      1
      2  key51359    =MATCH(A2;sheet1!$A$2:$A$100001;)       =INDEX(sheet1!$B$2:$B$100001;B2)
      3  key41232    =MATCH(A3;sheet1!$A$2:$A$100001;)       =INDEX(sheet1!$B$2:$B$100001;B3)
      4  key10102    =MATCH(A4;sheet1!$A$2:$A$100001;)       =INDEX(sheet1!$B$2:$B$100001;B4)
    ...  ...         ...                                     ...
  99999  key4153     =MATCH(A99999;sheet1!$A$2:$A$100001;)   =INDEX(sheet1!$B$2:$B$100001;B99999)
 100000  key12818    =MATCH(A100000;sheet1!$A$2:$A$100001;)  =INDEX(sheet1!$B$2:$B$100001;B100000)
 100001  key35032    =MATCH(A100001;sheet1!$A$2:$A$100001;)  =INDEX(sheet1!$B$2:$B$100001;B100001)
 100002
Run Code Online (Sandbox Code Playgroud)

3)查询表:( vbalookup版)

       A          B
     1
     2  key51359    {=vbalookup(A2:A50001;sheet1!$A$2:$B$100001;2)}
     3  key41232    formula in B2
     4  key10102    ... extends to
   ...  ...         ...
 50000  key91021    ... 
 50001  key42       ... cell B50001
 50002  key21873    {=vbalookup(A50002:A100001;sheet1!$A$2:$B$100001;2)}
 50003  key31415    formula in B50001 extends to
   ...  ...         ...
 99999  key4153     ... cell B100001
100000  key12818    ... (select whole range, and press
100001  key35032    ... CTRL+SHIFT+ENTER to make it an array formula)
100002
Run Code Online (Sandbox Code Playgroud)

注意:对于某些(外部内部)原因,vbalookup一次无法返回超过65536个数据.所以我不得不将数组公​​式分成两部分.

以及相关的VBA代码:

Function vbalookup(lookupRange As Range, refRange As Range, dataCol As Long) As Variant
  Dim dict As New Scripting.Dictionary
  Dim myRow As Range
  Dim I As Long, J As Long
  Dim vResults() As Variant

  ' 1. Build a dictionnary
  For Each myRow In refRange.Columns(1).Cells
    ' Append A : B to dictionnary
    dict.Add myRow.Value, myRow.Offset(0, dataCol - 1).Value
  Next myRow

  ' 2. Use it over all lookup data
  ReDim vResults(1 To lookupRange.Rows.Count, 1 To lookupRange.Columns.Count) As Variant
  For I = 1 To lookupRange.Rows.Count
    For J = 1 To lookupRange.Columns.Count
      If dict.Exists(lookupRange.Cells(I, J).Value) Then
        vResults(I, J) = dict(lookupRange.Cells(I, J).Value)
      End If
    Next J
  Next I

  vbalookup = vResults
End Function
Run Code Online (Sandbox Code Playgroud)

注意:Scripting.Dictionary需要Microsoft Scripting Runtime手动添加参考(Excel VBA窗口中的工具 - >参考菜单)

结论:

在这种情况下,使用字典的VBA比使用VLOOKUP快100倍,比MATCH/INDEX快20倍

  • 我正在尝试使用你的vbalookup替换我的excel中的vlookup功能.我在一个选项卡中有数据,在其他选项卡中有各种公式.如果我做对了,我应该使用与vlookup相同的语法:vlookup(value,range,col).现在问题在于:它总是以#value作为结果返回给我.你看到了同样的吗? (3认同)

kev*_*999 6

您也可以考虑使用"双Vlookup"方法(不是我的想法 - 在别处看到).我在工作表2(随机分类)上的100,000个查找值上测试了它,其数据集与您在表1中描述的数据集相同,并且在不到4秒的时间内进行了计时.代码也有点简单.

Sub FastestVlookup()

    With Sheet2.Range("B1:B100000")
        .FormulaR1C1 = _
        "=IF(VLOOKUP(RC1,Sheet1!R1C1:R100000C1,1)=RC1,VLOOKUP(RC1,Sheet1!R1C1:R100000C2,2),""N/A"")"
        .Value = .Value
    End With

End Sub
Run Code Online (Sandbox Code Playgroud)


小智 5

切换到Excel 2013并使用数据模型.在那里,您可以在两个表中定义具有唯一ID键的列,并将这两个表与数据透视表中的关系绑定.如果绝对必要,您可以使用Getpivotdata()填充第一个表.我有一个~250K行的表在类似的~250K行表中执行vlookup.停止Excel一小时后计算它.使用数据模型花了不到10秒.