jueves, 1 de marzo de 2018

VBA: El objeto .Dictionary

Existen en VBA para Excel varios y diferentes métodos para almacenar nuestra información.
Dos de los más frecuentes son:
1- las Array (las matrices) ya sean simples o multidimensionales
2- las Collection
3- otras (en ListBox, ComboBox, etc.)

Lo que veremos hoy es el objeto .Dictionary, posiblemente más potente que todas las demás... siempre dependiendo de qué necesitemos.

Una característica importante de un Diccionario es el uso de claves únicas (ideal para crear listas de elementos únicos), esto es, no es necesario buscar un elemento mediante un 'bucle' o mediante el uso de una función 'application.match'. Sin duda, es una gran ventaja de un diccionario en comparación con una matriz.

Por otra parte, la forma en que el Diccionario almacena elementos es comparable al objeto Colección.
El Diccionario tiene algunas propiedades-funciones-métodos como .keys, .items, .removeall o .count entre otras, que pueden ser ventajosas en comparación con el uso de una Colección.


Ya que hablamos de claves únicas es importante conocer la propiedad .CompareMode de los 'Diccionarios' que nos permiten discriminar mayúsculas de minúsculas:

MiDiccionario.CompareMode = vbBinaryCompare    'diferencia entre mayúsculas y minúsculas
MiDiccionario.CompareMode = vbTextCompare      'NO diferencia entre mayúsculas y minúsculas


el valor por defecto es 0 ó vbBinaryCompare, es decir sí diferencia...


El primer paso será crear el Dictionario. Mi forma preferida es:

Dim MiDiccionario As Object
Set MiDiccionario = CreateObject("Scripting.Dictionary")



Comenzaremos 'cargando' de datos nuestro Diccionario.
Podemos conseguirlo con dos métodos: .Add o .Item
Veamos el uso indistinto para cargar el mismo dato (ya con el objeto creado):

MiDiccionario.Add Key:="Uno" , Item:="Excel"

o también

MiDiccionario.Item("Uno") = "Excel"


Siempre que el elemento (Item) no existe se agregará al 'Diccionario'; sin embargo hay una diferencia entre los dos métodos.
El método .Add actúa igual que una Collection, por tanto si el elemento existe se generará un error.
Por ejemplo:

Sub Diccionarios_1()
Dim MiDiccionario As Object
Set MiDiccionario = CreateObject("Scripting.Dictionary")

MiDiccionario.Add Key:="Uno", Item:="Excel"
MiDiccionario.Add Key:="Uno", Item:="Excelforo"

End Sub


Al ejecutarla comprobamos nos devuelve el mensaje de error 457, donde nos indica que la 'clave' ya está asociada con un elemento de la colección.

Sin embargo al usar el segundo de las formas, con Item:

Sub Diccionarios_2()
Dim MiDiccionario As Object
Set MiDiccionario = CreateObject("Scripting.Dictionary")

MiDiccionario.Item("Uno") = "Excel"
MiDiccionario.Item("Uno") = "Excelforo"

MsgBox MiDiccionario.Item("Uno")
End Sub


Al ejecutar la macro vemos que se ha cargado sin error, manteniendo el último elemento cargado!!

Una alternativa, empleado igualmente el método .Item es cargar a una variable el elemento:

Sub Diccionarios_3()
Dim MiDiccionario As Object
Set MiDiccionario = CreateObject("Scripting.Dictionary")

y = MiDiccionario.Item("Uno")
y = MiDiccionario.Item("uno")

MsgBox Join(MiDiccionario.keys, vbLf)
End Sub



Un ejemplo sería obtener un listado de países únicos (independientemente de cómo aparezcan-en mayúscula o minúscula):

Sub Diccionarios_Unicos()
Dim MiDiccionario As Object
Set MiDiccionario = CreateObject("Scripting.Dictionary")

'por defecto distingue mayúsculas de minúsculas...
'per cambiando la propiedad .CompareMode conseguimos no discrimine
MiDiccionario.comparemode = vbTextCompare

For Each elto In Array("España", "ESPAÑA", "México", "MÉXICO", "méxico", "Colombia")
    y = MiDiccionario.Item(elto)
Next elto

'países únicos
With MiDiccionario
    MsgBox "Num eltos: " & .Count & vbCrLf & _
        Join(.Keys, vbLf)
End With
End Sub

Al ejecutar la macro vemos en nuestra ventana emergente el listado de tres países: 'España', 'México' y 'Colombia'
Esto es, de los primeros elementos cargados.


Otro método interesante de un 'Diccionario' es el método .Exists con el que verificamos la existencia de una clave en el diccionario creado...
Veamos un ejemplo:

Sub CheckPais()
Dim MiDiccionario As Object
Set MiDiccionario = CreateObject("Scripting.Dictionary")

With MiDiccionario
    'para que no discrimine mayusculas ni minúsculas
    .CompareMode = vbTextCompare
    
    ' añadimos tres países al diccionario
    .Add Key:="España", Item:=1000
    .Add Key:="México", Item:=2000
    .Add Key:="Colombia", Item:=3000
    
    Dim sPais As String
    'Preguntamsoo al usuario por un país
    sPais = InputBox("Introduce un país...")
    
    'empleamos el método .Exists
    'para determinar si existe o  no el pais introducido
    If .Exists(sPais) Then
        MsgBox sPais & " ya existe, y su valor es " & MiDiccionario(sPais)
    Else
        MsgBox sPais & " no existe."
    End If
End With
Set MiDiccionario = Nothing
End Sub



Dos último métodos que veremos son: .Remove y .RemoveAll
El primero .Remove elimina u elemento concreto que indiquemos, así como su clave.
El segundo limpia todo el 'Diccionario', pero dejando activo el objeto.

Sub EliminarElementos()

Dim MiDiccionario As Object
Set MiDiccionario = CreateObject("Scripting.Dictionary")

With MiDiccionario
    'para que no discrimine mayusculas ni minúsculas
    .CompareMode = vbTextCompare
    
    'añadimos tres países al diccionario
    .Add Key:="España", Item:=1000
    .Add Key:="México", Item:=2000
    .Add Key:="Colombia", Item:=3000
    MsgBox "Número elementos: " & .Count

    'eliminamos un elemento concreto
    .Remove "España"
    MsgBox "Número elementos: " & .Count
    
    'y el resto de elementos
    .RemoveAll
    MsgBox "Número elementos: " & .Count
End With
End Sub



Y hasta aquí la breve introducción a este objeto .Dictionary

3 comentarios:

  1. muy interesante, esta opción , saludos maestro!!.

    ResponderEliminar
  2. He leído en muchas páginas tanto en inglés como en español pero ninguna lo explica tan fácil y sencillo como tú. Gracias. Saludos.

    ResponderEliminar

Nota: solo los miembros de este blog pueden publicar comentarios.