Je recherche des alternatives à vlookup, avec des performances améliorées dans le contexte qui nous intéresse.
Le contexte est le suivant:
VLOOKUP
est FALSE
)Un schéma pour expliquer:
Fiche de référence: ("sheet1"
)
A B
1
2 key1 data1
3 key2 data2
4 key3 data3
... ... ...
99999 key99998 data99998
100000 key99999 data99999
100001 key100000 data100000
100002
Feuille de recherche:
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
Sur mon Core i7 M 620 @ 2,67 GHz, cela se calcule en ~ 10 minutes
Existe-t-il des alternatives à RECHERCHEV avec de meilleures performances dans ce contexte?
J'ai considéré les alternatives suivantes:
La performance comparée est:
Utilisation de la même feuille de référence
1) Feuille de recherche: (version de formule de tableau 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
2) Feuille de recherche: (version match + index)
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
3) Feuille de recherche: (version 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
NB : Pour une raison (externe interne), vbalookup ne parvient pas à renvoyer plus de 65536 données à la fois. J'ai donc dû diviser la formule matricielle en deux.
et le code VBA associé:
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
NB: Scripting.Dictionary
nécessite une référence à Microsoft Scripting Runtime
qui doit être ajouté manuellement (menu Outils-> Références dans la fenêtre Excel VBA)
Conclusion :
Dans ce contexte, VBA utilisant un dictionnaire est 100 fois plus rapide que VLOOKUP et 20 fois plus rapide que MATCH/INDEX
Vous pouvez également envisager d'utiliser la méthode "double Vlookup" (pas mon idée - vue ailleurs). Je l'ai testé sur 100 000 valeurs de recherche sur la feuille 2 (triées au hasard) avec un ensemble de données identique à celui que vous avez décrit sur la feuille 1, et je l'ai chronométré en un peu moins de 4 secondes. Le code est également un peu plus simple.
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
Basculez vers Excel 2013 et utilisez le modèle de données. Vous pouvez y définir une colonne avec des clés d'ID uniques dans les deux tables et lier ces deux tables avec une relation dans le tableau croisé dynamique. Si nécessaire, vous pouvez utiliser Getpivotdata () pour remplir le premier tableau. J'avais une table de ~ 250K lignes faisant vlookup dans la table de ~ 250K lignes similaire. Excel arrêté le calcul après une heure. Avec le modèle de données, il a fallu moins de 10 secondes.