VBA a-t-il une structure de dictionnaire? Comme clé <> valeur tableau?
Oui.
Définissez une référence au runtime MS Scripting ('Microsoft Scripting Runtime'). Selon le commentaire de @ regjo, allez dans Outils-> Références et cochez la case "Microsoft Scripting Runtime".
Créez une instance de dictionnaire en utilisant le code ci-dessous:
Set dict = CreateObject("Scripting.Dictionary")
ou
Dim dict As New Scripting.Dictionary
Exemple d'utilisation:
If Not dict.Exists(key) Then
dict.Add key, value
End If
N'oubliez pas de régler le dictionnaire sur Nothing
lorsque vous avez fini de l'utiliser.
Set dict = Nothing
VBA a l'objet collection:
Dim c As Collection
Set c = New Collection
c.Add "Data1", "Key1"
c.Add "Data2", "Key2"
c.Add "Data3", "Key3"
'Insert data via key into cell A1
Range("A1").Value = c.Item("Key2")
L'objet Collection
effectue des recherches à base de clé en utilisant un hachage, donc c'est rapide.
Vous pouvez utiliser une fonction Contains()
pour vérifier si une collection particulière contient une clé:
Public Function Contains(col As Collection, key As Variant) As Boolean
On Error Resume Next
col(key) ' Just try it. If it fails, Err.Number will be nonzero.
Contains = (Err.Number = 0)
Err.Clear
End Function
Edit 24 June 2015: Plus court Contains()
grâce à @TWiStErRob.
Edit 25 September 2015: Ajouté Err.Clear()
grâce à @scipilot.
VBA ne dispose pas d'une implémentation interne d'un dictionnaire, mais vous pouvez toujours utiliser l'objet dictionnaire à partir de MS Scripting Runtime Library.
Dim d
Set d = CreateObject("Scripting.Dictionary")
d.Add "a", "aaa"
d.Add "b", "bbb"
d.Add "c", "ccc"
If d.Exists("c") Then
MsgBox d("c")
End If
Un exemple de dictionnaire supplémentaire utile pour contenir la fréquence des occurrences.
En dehors de la boucle:
Dim dict As New Scripting.dictionary
Dim MyVar as String
Dans une boucle:
'dictionary
If dict.Exists(MyVar) Then
dict.Item(MyVar) = dict.Item(MyVar) + 1 'increment
Else
dict.Item(MyVar) = 1 'set as 1st occurence
End If
Pour vérifier la fréquence:
Dim i As Integer
For i = 0 To dict.Count - 1 ' lower index 0 (instead of 1)
Debug.Print dict.Items(i) & " " & dict.Keys(i)
Next i
En s'appuyant sur réponse de cjrh , nous pouvons créer une fonction Contains ne nécessitant aucune étiquette (je n'aime pas utiliser les étiquettes).
Public Function Contains(Col As Collection, Key As String) As Boolean
Contains = True
On Error Resume Next
err.Clear
Col (Key)
If err.Number <> 0 Then
Contains = False
err.Clear
End If
On Error GoTo 0
End Function
Pour un de mes projets, j’ai écrit un ensemble de fonctions d’aide permettant de faire en sorte que Collection
se comporte davantage comme un Dictionary
. Il autorise toujours les collections récursives. Vous remarquerez que Key vient toujours en premier parce que c'était obligatoire et plus logique dans mon implémentation. J'ai également utilisé uniquement les touches String
. Vous pouvez le changer si vous le souhaitez.
J'ai renommé ceci pour le définir car il écrasera les anciennes valeurs.
Private Sub cSet(ByRef Col As Collection, Key As String, Item As Variant)
If (cHas(Col, Key)) Then Col.Remove Key
Col.Add Array(Key, Item), Key
End Sub
La substance err
concerne les objets puisque vous transmettriez des objets à l'aide de set
et des variables sans. Je pense que vous pouvez simplement vérifier si c'est un objet, mais j'étais pressé par le temps.
Private Function cGet(ByRef Col As Collection, Key As String) As Variant
If Not cHas(Col, Key) Then Exit Function
On Error Resume Next
err.Clear
Set cGet = Col(Key)(1)
If err.Number = 13 Then
err.Clear
cGet = Col(Key)(1)
End If
On Error GoTo 0
If err.Number <> 0 Then Call err.raise(err.Number, err.Source, err.Description, err.HelpFile, err.HelpContext)
End Function
La raison de ce post ...
Public Function cHas(Col As Collection, Key As String) As Boolean
cHas = True
On Error Resume Next
err.Clear
Col (Key)
If err.Number <> 0 Then
cHas = False
err.Clear
End If
On Error GoTo 0
End Function
Ne jette pas si ça n'existe pas. Veille simplement à ce qu'il soit supprimé.
Private Sub cRemove(ByRef Col As Collection, Key As String)
If cHas(Col, Key) Then Col.Remove Key
End Sub
Obtenez un tableau de clés.
Private Function cKeys(ByRef Col As Collection) As String()
Dim Initialized As Boolean
Dim Keys() As String
For Each Item In Col
If Not Initialized Then
ReDim Preserve Keys(0)
Keys(UBound(Keys)) = Item(0)
Initialized = True
Else
ReDim Preserve Keys(UBound(Keys) + 1)
Keys(UBound(Keys)) = Item(0)
End If
Next Item
cKeys = Keys
End Function
Le dictionnaire d'exécution de script semble contenir un bogue qui peut ruiner votre conception à un stade avancé.
Si la valeur du dictionnaire est un tableau, vous ne pouvez pas mettre à jour les valeurs des éléments contenus dans le tableau via une référence au dictionnaire.
Si, pour une raison quelconque, vous ne pouvez pas installer de fonctionnalités supplémentaires dans votre Excel ou ne le souhaitez pas, vous pouvez également utiliser des tableaux, du moins pour les problèmes simples. En tant que WhatIsCapital, vous mettez le nom du pays et la fonction vous renvoie son capital.
Sub arrays()
Dim WhatIsCapital As String, Country As Array, Capital As Array, Answer As String
WhatIsCapital = "Sweden"
Country = Array("UK", "Sweden", "Germany", "France")
Capital = Array("London", "Stockholm", "Berlin", "Paris")
For i = 0 To 10
If WhatIsCapital = Country(i) Then Answer = Capital(i)
Next i
Debug.Print Answer
End Sub
Tous les autres ont déjà mentionné l'utilisation de la version scripting.runtime de la classe Dictionary. Si vous ne parvenez pas à utiliser cette DLL, vous pouvez également utiliser cette version, ajoutez-la simplement à votre code.
https://github.com/VBA-tools/VBA-Dictionary/blob/master/Dictionary.cls
Il est identique à la version de Microsoft.