与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
但我更好奇为什么我似乎无法按编号迭代这些项目。
答案 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