Цикл по Scripting.Dictionary с использованием индекса / номера элемента

Похожий наЭта проблемапри использованииScripting.Dictionary объект в VBA, результат кода ниже является неожиданным.

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

Используя нулевой индекс, достигается тот же результат:

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

Наблюдая за объектом, я действительно вижу, что у него есть два элемента, ключ для вновь добавленного1как добавлено изi, Если я увеличу этот цикл до большего числа, то количество элементов в словаре будет увеличено, один раз для каждого цикла.

I have tested this in Office/VBA 2003, 2010, and 2013. All exhibit the same behavior, and I expect other versions (2007) will as well.

Я могу обойти это с другими методами зацикливания, но это застало меня врасплох, когда я пытался хранить объекты и получалobject expected error наs = d.Item(i) линия.

Для протокола, я знаю, что могу делать такие вещи:

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

Но мне более любопытно, почему я не могу перебирать элементы по номерам.

 Gaffi02 июл. 2012 г., 17:32
@assylias Я вижу это в документации.Item(Key) но я также вижу.Key(Key)хотя я не уверен, как использоватьKey метод ... Есть ли способ итерации по номеру элемента?

Ответы на вопрос(3)

Решение Вопроса

документацияItem property:

Sets or returns an item for a specified key in a Dictionary object.

В вашем случае у вас нет предмета, ключ которого1 так делать:

s = d.Item(i)

на самом деле создает новую пару ключ / значение в вашем словаре, и значение пусто, потому что вы не использовали необязательныйnewItem аргумент.

Словарь также имеетItems method что позволяет перебирать индексы:

a = d.Items
For i = 0 To d.Count - 1
    s = a(i)
Next i
 02 июл. 2012 г., 17:43
@Gaffi Смотрите мои правки
 Gaffi02 июл. 2012 г., 17:42
И с помощью этой информации я изменил вопрос, чтобы он не включал «ошибку» формулировка.
 02 июл. 2012 г., 18:04
+1 Красиво сделано :)
 Gaffi02 июл. 2012 г., 17:45
Это выглядит так. Спасибо!
 Gaffi02 июл. 2012 г., 17:38
Я следую этому, но нет ли способа перебирать / читать по индексу / номеру элемента?Seems like a silly implementation, if you ask me. ;-)

что D.ITEMS - это метод, который возвращает массив. Зная это, нам не нужен вариантный массив a (i) [см. Предостережение ниже]. Нам просто нужно использовать правильный синтаксис массива.

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

KEYS работает так же

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

Этот синтаксис также полезен для функции SPLIT, которая может помочь сделать это более понятным. SPLIT также возвращает массив с нижними границами, равными 0. Таким образом, следующий текст выводит «C».

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

SPLIT - это функция. Его параметры указаны в первом наборе скобок. Методы и функции всегда используют первый набор скобок для параметров, даже если параметры не нужны. В примере SPLIT возвращает массив {"A", "B", "C", "D"}. Поскольку он возвращает массив, мы можем использовать второй набор скобок, чтобы идентифицировать элемент в возвращаемом массиве так же, как и любой другой массив.

CaveatЭтот более короткий синтаксис может быть не таким эффективным, как использование вариантного массива a () при итерации по всему словарю, поскольку более короткий синтаксис вызывает метод Items словаря при каждой итерации. Более короткий синтаксис лучше всего подходит для извлечения одного элемента по номеру из словаря.

d.Keys()(i) Метод - очень плохая идея, потому что при каждом вызове он будет заново создавать новый массив (у вас будет значительное снижение скорости).

Вот аналогScripting.Dictionary называется "хэш-таблица" класс из @ & quot; The Trick & quot ;, поддерживающий такой перечислитель:http://www.cyberforum.ru/blogs/354370/blog2905.html

Dim oDict As clsTrickHashTable

Sub aaa()
    Set oDict = New clsTrickHashTable

    oDict.Add "a", "aaa"
    oDict.Add "b", "bbb"

    For i = 0 To oDict.Count - 1
        Debug.Print oDict.Keys(i) & " - " & oDict.Items(i)
    Next
End Sub

Ваш ответ на вопрос