41

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

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

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

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

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

但我更好奇为什么我似乎无法按数字遍历项目。

4

4 回答 4

41

根据Item物业的文件:

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

在你的情况下,你没有一个项目的关键是1这样做:

s = d.Item(i)

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

Dictionary 还具有允许循环遍历索引的Items方法:

a = d.Items
For i = 0 To d.Count - 1
    s = a(i)
Next i
于 2012-07-02T15:31:26.977 回答
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 方法。较短的语法最适合从字典中按数字提取单个项目。

于 2012-12-05T03:37:12.100 回答
2

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

这是Scripting.Dictionary来自@TheTrick 的称为“哈希表”类的类似物,它支持这样的枚举器: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
于 2018-12-12T10:41:34.990 回答
0

我尝试了 Craig Hatmaker 的代码,通过遍历索引 i 来更改字典 d 中的值。d.Items(i) = s不工作。但d.Item(d.Keys(i)) = s奏效了。换句话说:您需要通过索引获取密钥并使用密钥来访问该项目。请注意,我先尝试了带有 s 的 Items(),然后尝试了没有 s 的 Item(Keys)。不确定这是否是好的编程并且在每种情况下都有效,但也许它可以帮助某人。

于 2021-05-07T04:04:14.053 回答