¿VBA tiene estructura de diccionario? ¿Como clave <> matriz de valores?
¿VBA tiene estructura de diccionario? ¿Como clave <> matriz de valores?
Respuestas:
Si.
Establezca una referencia al tiempo de ejecución de MS Scripting ('Microsoft Scripting Runtime'). Según el comentario de @ regjo, vaya a Herramientas-> Referencias y marque la casilla para 'Microsoft Scripting Runtime'.
Cree una instancia de diccionario con el siguiente código:
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 Nothing
cuando hayas terminado de usarlo.
Set dict = Nothing
keyed
.
Dim dict As New Scripting.Dictionary
sin la referencia. Sin la referencia, debe utilizar el CreateObject
método de enlace tardío para crear instancias de este objeto.
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 Collection
objeto realiza búsquedas basadas en claves utilizando un hash, por lo que es rápido.
Puede usar una Contains()
función para verificar si una colección 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 : más corto Contains()
gracias a @TWiStErRob.
Edición 25 de septiembre de 2015 : agregado Err.Clear()
gracias a @scipilot.
ContainsKey
; alguien que lea solo la invocación puede confundirla por verificar que contiene un valor particular.
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
Un ejemplo adicional de diccionario que es útil para contener la frecuencia de ocurrencia.
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 verificar 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
Partiendo de la respuesta de cjrh , podemos construir una función Contiene que no requiera 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 auxiliares para hacer que un Collection
comportamiento se parezca más a un Dictionary
. Todavía permite colecciones recursivas. Notarás que Key siempre viene primero porque era obligatorio y tenía más sentido en mi implementación. Yo también usé soloString
llaves. Puede volver a cambiarlo si lo desea.
Cambié el nombre de esto 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
El err
material es para objetos, ya que pasaría objetos usando set
y variables sin. Creo que puedes comprobar si es un objeto, pero me presionaron por el 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
El motivo de esta publicación ...
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
No tira si no existe. Solo se asegura de que se elimine.
Private Sub cRemove(ByRef Col As Collection, Key As String)
If cHas(Col, Key) Then Col.Remove Key
End Sub
Obtenga una variedad 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
El diccionario de tiempo de ejecución de secuencias de comandos 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.
Si por algún motivo no puede instalar funciones adicionales en su Excel o no desea hacerlo, también puede usar matrices, 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
Dim
palabra clave, Country
y Capital
debe declararse como Variantes debido al uso de Array()
, i
debe declararse (y debe ser si Option Explicit
está configurado), y el contador de bucle arrojará un error fuera de límite, más seguro para utilizar UBound(Country)
para el To
valor. También vale la pena señalar que, si bien la Array()
función es un atajo útil, no es la forma estándar de declarar matrices en VBA.
Todos los demás ya han mencionado el uso de la versión scripting.runtime de la clase Diccionario. 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éntico a la versión de Microsoft.