¿VBA tiene Estructura de Diccionario?


¿Tiene VBA estructura de diccionario? Como clave matriz de valor?

Author: DaveInCaz, 2009-05-27

9 answers

Sí.

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 'Microsoft Scripting Runtime'.

Ventana de Referencias

Cree una instancia de diccionario usando 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 olvide establecer el diccionario en Nothing cuando haya terminado de usarlo.

Set dict = Nothing 
 297
Author: Mitch Wheat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-27 10:53:30

VBA tiene el objeto 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")

El objeto Collection realiza búsquedas basadas en claves usando un hash para que sea 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

Editar 24 de junio de 2015: Más corto Contains() gracias a @TWiStErRob.

Editar 25 de septiembre de 2015 : Agregado Err.Clear() gracias a @scipilot.

 158
Author: Caleb Hattingh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-12 20:04:46

VBA no tiene una implementación interna de un diccionario, pero desde VBA aún puede usar el objeto dictionary de la Biblioteca de tiempo de ejecución de MS Scripting.

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
 37
Author: Jarmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-27 12:19:03

Un ejemplo de diccionario adicional 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 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
 27
Author: John M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-26 13:04:35

Construyendo 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 auxiliares para hacer que un Collection se comporte más como un Dictionary. Todavía permite colecciones recursivas. Notarás que la clave siempre viene primero porque era obligatoria y tenía más sentido en mi implementación. También usé solo las teclas String. Puedes cambiarlo si quieres.

Conjunto

I renombrado esto a set porque sobrescribirá 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

Get

El material err es para objetos ya que pasarías objetos usando set y variables sin. Creo que puedes comprobar si es un objeto, pero estaba presionado 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

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

Eliminar

No lanza si no existe. Sólo se asegura de que se quite.

Private Sub cRemove(ByRef Col As Collection, Key As String)
    If cHas(Col, Key) Then Col.Remove Key
End Sub

Teclas

Obtener una matriz 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
 9
Author: Evan Kennedy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:44

El diccionario de tiempo de ejecución de scripting parece tener un error que puede arruinar su diseño en etapas avanzadas.

Si el valor del diccionario es un array, no puede actualizar los valores de los elementos contenidos en el array a través de una referencia al diccionario.

 6
Author: Kalidas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-02 18:36:53

Sí. Para VB6, VBA (Excel), y VB.NET

 6
Author: Matthew Flaschen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-26 12:13:23

Si por alguna razón, no puede instalar características adicionales a su Excel o no desea, 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
 4
Author: user2604899,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-22 12:29:55

Todos los demás ya han mencionado el uso del scripting.versión en tiempo de ejecución 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éntico a la versión de Microsoft.

 2
Author: Michiel van der Blonk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-23 01:27:04