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

38

Похожий наЭта проблемапри использовании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

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

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

Ваш Ответ

3   ответа
38

документация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
И с помощью этой информации я изменил вопрос, чтобы он не включал «ошибку» формулировка. Gaffi
+1 Красиво сделано :)
@Gaffi Смотрите мои правки
Это выглядит так. Спасибо! Gaffi
Я следую этому, но нет ли способа перебирать / читать по индексу / номеру элемента?Seems like a silly implementation, if you ask me. ;-) Gaffi
37

что 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 словаря при каждой итерации. Более короткий синтаксис лучше всего подходит для извлечения одного элемента по номеру из словаря.

0

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

Похожие вопросы