para - ¿VBA tiene estructura de diccionario?
modulos vba excel (9)
A partir de la respuesta de cjrh , podemos construir una función Contains que no requiere etiquetas (no me gusta usar etiquetas).
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
Para un proyecto mío, escribí un conjunto de funciones de ayuda para hacer que una Collection
comporte más como un Dictionary
. Todavía permite colecciones recursivas. Notarás que Key siempre es lo primero porque era obligatorio y tenía más sentido en mi implementación. También utilicé sólo teclas de String
. Puedes volver a cambiarlo si quieres.
Conjunto
Cambié el nombre de este para establecer porque sobrescribirá los valores antiguos.
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
Obtener
El err
es para objetos, ya que pasarías objetos usando set
y variables sin. Creo que puedes verificar si es un objeto, pero me presionaron para obtener tiempo.
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
Tiene
La razón de este 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
retirar
No lanza si no existe. Sólo se asegura de que sea eliminado.
Private Sub cRemove(ByRef Col As Collection, Key As String)
If cHas(Col, Key) Then Col.Remove Key
End Sub
Llaves
Obtener una serie de claves.
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
¿VBA tiene estructura de diccionario? ¿Como clave <> matriz de valor?
El diccionario de ejecución de scripts parece tener un error que puede arruinar su diseño en etapas avanzadas.
Si el valor del diccionario es una matriz, no puede actualizar los valores de los elementos contenidos en la matriz a través de una referencia al diccionario.
Sí.
Establecer una referencia al tiempo de ejecución de MS Scripting (''Microsoft Scripting Runtime''). De acuerdo con el comentario de @ regjo, vaya a Herramientas-> Referencias y marque la casilla "Microsoft Scripting Runtime".
Crea una instancia de diccionario usando el código de abajo:
Set dict = CreateObject("Scripting.Dictionary")
o
Dim dict As New Scripting.Dictionary
Ejemplo de uso:
If Not dict.Exists(key) Then
dict.Add key, value
End If
No olvides configurar el diccionario en Nothing
cuando hayas terminado de usarlo.
Set dict = Nothing
Si, por cualquier motivo, no puede instalar funciones adicionales en su Excel o no lo desea, también puede usar arreglos, al menos para problemas simples. Como WhatIsCapital pones el nombre del país y la función te devuelve su 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
Todos los demás ya han mencionado el uso de la versión scripting.runtime de la clase Dictionary. Si no puede usar esta DLL, también puede usar esta versión, simplemente agréguela a su código.
https://github.com/VBA-tools/VBA-Dictionary/blob/master/Dictionary.cls
Es idéntica a la versión de Microsoft.
Un ejemplo de diccionario adicional que es útil para contener la frecuencia de aparición.
Fuera del bucle:
Dim dict As New Scripting.dictionary
Dim MyVar as String
Dentro de un bucle:
''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
Para comprobar la frecuencia:
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
VBA no tiene una implementación interna de un diccionario, pero desde VBA aún puede usar el objeto de diccionario 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
VBA tiene el objeto de colección:
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")
El objeto Collection
realiza búsquedas basadas en claves utilizando un hash, por lo que es rápido.
Puede usar una función Contains()
para verificar si una colección en particular contiene una clave:
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
Edición 24 de junio de 2015 : Shorter Contains()
gracias a @TWiStErRob.
Edición 25 de septiembre de 2015 : Se agregó Err.Clear()
gracias a @scipilot.