使用索引/项目编号循环访问Scripting.Dictionary

时间:2012-07-02 15:18:56

标签: vba dictionary

this issue类似,在VBA中使用Scripting.Dictionary对象时,下面代码的结果是意外的。

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添加。如果我将此循环增加到更高的数字,则字典中的项目数会增加,每次循环一次。

我在Office / VBA 2003,2010和2013中对此进行了测试。所有人都表现出相同的行为,我希望其他版本(2007)也会出现。

我可以使用其他循环方法解决这个问题,但是当我尝试存储对象并且在s = d.Item(i)行上遇到对象预期错误时,这让我措手不及。 / p>

为了记录,我知道我可以做这样的事情:

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

但我更好奇为什么我似乎无法按编号迭代这些项目。

5 个答案:

答案 0 :(得分:39)

根据the documentation of the Item property

  

在Dictionary对象中设置或返回指定键的项目。

在您的情况下,您没有关键字为1的项目,所以:

s = d.Item(i)

实际上在字典中创建了一个新的键/值对,并且该值为空,因为您没有使用可选的newItem参数。

字典还有Items method,允许循环索引:

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

答案 1 :(得分:38)

添加到assylias的答案 - assylias向我们展示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”}。由于它返回一个数组,我们可以使用第二组括号来识别返回数组中的元素,就像我们对任何数组一样。

警告:这种较短的语法可能不如在迭代整个字典时使用变量数组a()那样有效,因为较短的语法会在每次迭代时调用字典的Items方法。较短的语法最适合从字典中按数字提取单个项目。

答案 2 :(得分:1)

使用d.Keys()(i)方法是一个非常糟糕的主意,因为在每次调用时,它都会重新创建一个新的数组(您将大大降低速度)。

这里是Scripting.Dictionary的类似物,它来自@“ The Trick”,称为“哈希表”类,它支持以下枚举器: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

答案 3 :(得分:0)

我尝试了 Craig Hatmaker 的代码,通过循环索引 i 来更改字典 d 中的值。 d.Items(i) = s 不起作用。但是 d.Item(d.Keys(i)) = s 奏效了。换句话说:您需要通过索引获取键并使用可以访问该项目的键来解决。 请注意,我首先尝试了带 s 的 Items(),然后是不带 s 的 Item(Keys)。 不确定这是否是好的编程并且适用于所有情况,但也许它可以帮助某人。

答案 4 :(得分:-1)

它基于零,所以你的循环应该从0到d.Count - 1