Performance 如何优化vlookup以获得高搜索数?(VLOOKUP的替代方案)

Performance 如何优化vlookup以获得高搜索数?(VLOOKUP的替代方案),performance,excel,dictionary,vlookup,vba,Performance,Excel,Dictionary,Vlookup,Vba,我正在寻找vlookup的替代品,在感兴趣的背景下提高性能 背景如下: 我有一个很大的{key;data}数据集(~100000条记录) 我想在数据集上执行很多VLOOKUP操作(典型的用法是对整个数据集重新排序) 我的数据集没有重复的密钥 我只寻找精确匹配(VLOOKUP的最后一个参数是FALSE) 要解释的模式: 参考页:(“sheet1”) 查阅表格: A B 1 2 key51359 =VLOOKUP(A2;sheet1

我正在寻找vlookup的替代品,在感兴趣的背景下提高性能

背景如下:

  • 我有一个很大的{key;data}数据集(~100000条记录)
  • 我想在数据集上执行很多VLOOKUP操作(典型的用法是对整个数据集重新排序)
  • 我的数据集没有重复的密钥
  • 我只寻找精确匹配(
    VLOOKUP
    的最后一个参数是
    FALSE
要解释的模式:

参考页:(
“sheet1”

查阅表格:

        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
在我的核心i7 M 620@2.67 GHz上,这只需约10分钟即可计算


在这种情况下,有没有比VLOOKUP性能更好的替代方案?

我考虑了以下替代方案:

  • VLOOKUP阵列公式
  • 匹配/索引
  • VBA(使用字典)
比较性能为:

  • VLOOKUP简单公式:~10分钟
  • VLOOKUP阵列公式:~10分钟(1:1性能指数)
  • 匹配/索引:约2分钟(5:1性能索引)
  • VBA(使用字典):~6秒(100:1性能指数)
使用相同的参考页

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

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

3) 查找表:(vbalookup版本)

NB:由于某些(外部-内部)原因,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
注意:
Scripting.Dictionary
要求引用
Microsoft脚本运行时
,必须 手动添加(Excel VBA窗口中的工具->参考菜单)

结论:


在此上下文中,使用字典的VBA比使用VLoopy快100X,比匹配/索引< /P> >P>快20X。您也可能想考虑使用“双VLoopUp”方法(不是我的想法——在别处看到)。我在第2页的100000个查找值(随机排序)上测试了它,数据集与您在第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

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

值修复:在构建字典时检查空白单元格。如果单元格为空,请退出。

我正在尝试使用vbalookup替换excel中的vlookup功能。我在一个选项卡中有数据,在另一个选项卡中有各种公式。如果我做对了,我应该使用与vlookup相同的语法:vlookup(value,range,col)。现在的问题是:结果总是返回我的值。您看到了吗?您也可以使用Set dict=CreateObject(“scripting.dictionary”),而不是将其声明为scripting.dictionary,这不需要额外的VBA参考,代码与默认的VBA安装兼容如果有人找到Fatsave问题的答案,请也在这里发布:您能解释一下您的代码吗。应该做哪些更改?所有字段都会得到此值:“#名称?”如果您得到的是“#名称?”错误,则可能是您在代码中拼错了“VLOOKUP”,或者您有一个“(”在错误的位置。请检查并重试。对于如此大的数据集,Excel可能不是一个好选择。使用专业数据库,如*SQL或MS access会更好
         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
       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
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
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