2012-07-02 12 views
32

Similar a this issue, cuando se utiliza un objeto Scripting.Dictionary en VBA, el resultado del código siguiente es inesperado.Looping a través de un Scripting.Dictionary utilizando el índice/número de artículo

Option Explicit 

Sub test() 

    Dim d As Variant 
    Dim i As Integer 
    Dim s As String 
    Set d = CreateObject("Scripting.Dictionary") 

    d.Add "a", "a" 
    Debug.Print d.Count ' Prints '1' as expected 

    For i = 1 To d.Count 
     s = d.Item(i) 
     Debug.Print s ' Prints ' ' (null) instead of 'a' 
    Next i 

    Debug.Print d.Count ' Prints '2' instead of '1' 

End Sub 

El uso de un índice basado en cero, el mismo resultado se logra:

For i = 0 To d.Count - 1 
    s = d.Item(i) 
    Debug.Print s 
Next i 

Observando el objeto, realmente puedo ver que tiene dos elementos, la clave para el recién añadido es 1, como se agregó desde i. Si aumento este ciclo a un número más alto, entonces la cantidad de elementos en el diccionario aumenta, una vez para cada ciclo.

He probado esto en Office/VBA 2003, 2010 y 2013. Todos exhiben el mismo comportamiento, y espero que otras versiones (2007) también lo hagan.

puedo trabajar alrededor de este bucle con otros métodos, pero esto me tomó por sorpresa cuando estaba tratando de almacenar objetos y estaba recibiendo un error esperado objeto en la línea s = d.Item(i).

Para el registro, sé que puedo hacer cosas como esta:

For Each v In d.Keys 
    Set o = d.item(v) 
Next v 

pero estoy más curioso acerca de por qué me parece que no puede iterar a través de los artículos por número.

+2

@assylias Veo eso en la documentación '.Item (Key)' pero también veo '.Key (Key)', aunque no estoy seguro de cómo usar el método 'Key' ... ¿Hay una forma de iterar por número de artículo? – Gaffi

Respuesta

30

Según the documentation of the Item property:

Establece o devuelve un artículo para una clave especificada en un objeto Dictionary.

En su caso, usted no tiene un elemento cuya clave es 1 hacerlo:

s = d.Item(i) 

en realidad crea un nuevo par clave/valor en su diccionario, y el valor está vacío porque se no ha usado el argumento opcional newItem.

El diccionario también tiene la Items method que permite un bucle a través de los índices:

a = d.Items 
For i = 0 To d.Count - 1 
    s = a(i) 
Next i 
+2

Lo sigo, pero ¿no hay forma, entonces, de iterar/leer por índice/número de artículo? * Parece una implementación tonta, si me preguntas. ; -) * – Gaffi

+0

Y con esta información, he cambiado la pregunta para que no incluya la fraseología 'error'. – Gaffi

+0

@ Gaffi Ver mi edición – assylias

-1

Se basa cero por lo que su bucle debe ser de 0 a d.Count - 1

+0

No creo que esa sea la solución correcta. Cuando comencé a escribir el código, también pensé que esto se basaba en cero, pero cambiar la estructura del bucle no solucionó el problema, todavía agrega un nuevo elemento. – Gaffi

+0

Bueno, dado que acaba de aceptar la solución basada en cero anterior, uno está un poco confundido. Y esa respuesta que aceptaste también dice que usar un índice que no existe agrega uno, uno se confunde aún más. Todavía toma todo tipo eh? –

+0

Su respuesta no fue incorrecta; simplemente no resolvió mi problema específico. Para el registro, no le di el -1. El problema es que usar '.Item (index)' no es correcto. En cambio, usar '.Items' (tenga en cuenta la 's') para crear una matriz de teclas le permitirá hacer lo que estaba buscando. – Gaffi

32

Adición a la contestación de assylias - assylias nos muestra d.Items es un método que devuelve una matriz. Sabiendo eso, no necesitamos la matriz variante a (i) [Ver la advertencia a continuación]. Solo necesitamos usar la sintaxis de matriz adecuada.

For i = 0 To d.Count - 1 
    s = d.Items()(i) 
    Debug.Print s 
Next i() 

CLAVES funciona de la misma manera

For i = 0 To d.Count - 1 
    Debug.Print d.Keys()(i), d.Items()(i) 
Next i 

Esta sintaxis también es útil para la función SPLIT que puede ayudar a hacer esto más claro. SPLIT también devuelve una matriz con límites inferiores a 0. Por lo tanto, lo siguiente imprime "C".

Debug.Print Split("A,B,C,D", ",")(2) 

SPLIT es una función.Sus parámetros están en el primer conjunto de paréntesis. Los métodos y las funciones siempre usan el primer conjunto de paréntesis para los parámetros, incluso si no se necesitan parámetros. En el ejemplo, SPLIT devuelve la matriz {"A", "B", "C", "D"}. Como devuelve una matriz, podemos usar un segundo conjunto de paréntesis para identificar un elemento dentro de la matriz devuelta tal como lo haríamos con cualquier matriz.

Caveat: Esta sintaxis más corta puede no ser tan eficiente como el uso de la matriz de la variante a() cuando iteración a través de todo el diccionario ya que la sintaxis más corta invoca método Artículos del diccionario con cada iteración. La sintaxis más corta es la mejor para obtener un solo elemento por número de un diccionario.

Cuestiones relacionadas