证明Excel VBA Scripting.Dictionary不保留项目插入的顺序

时间:2016-06-08 14:30:44

标签: arrays excel-vba dictionary vba excel

我正在尝试决定是否将Excel VBA Collection或Dictionary用于我的项目。由于几个原因,我倾向于字典,但我继续阅读当使用For.. Each循环来检索字典项或从字典Items()数组中读取项时,检索的顺序可能不是顺序项目已添加。这对我的应用程序来说是一个严重的问题,因此我尝试了许多测试用例,试图证明实际发生了这种顺序不匹配。到目前为止,我还没有能够创建出现这种情况的场景,包括以随机顺序添加和删除项目。

任何人都可以提供一个示例来证明检索顺序与Excel VBA Scripting.Dictionary的插入顺序不匹配吗?

1 个答案:

答案 0 :(得分:5)

没有人可以提供Scripting.Dictionary对象返回键/项的示例,其顺序与添加的顺序不同,因为Scripting.Dictionary 不会这样做。决不。如果您以渐进顺序添加以下键/项对,那么这就是它们的返回方式。

key  item
 1    A
 2    B
 3    C
 4    D

'enumerate by key
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")

dict.Add Key:=1, Item:="A"
dict.Add Key:=2, Item:="B"
dict.Add Key:=3, Item:="C"
dict.Add Key:=4, Item:="D"

Dim k As Variant
For Each k In dict.Keys
    Debug.Print k & " - " & dict.Item(k)
Next k

你可能指的是添加键的简写'覆盖'方法,而不检查它们是否存在。如果您尝试.Add存在错误457的密钥。但是,如果您只是将KeysItems写入字典,则如果密钥不存在,则将创建新密钥和项目,但如果密钥存在,则密钥保持不变并且项目将被覆盖。

key  item
 1    A
 2    B
 3    C
 4    D
 2    E

'enumerate by key
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")

dict.Item(1) = "A"
dict.Item(2) = "B"
dict.Item(3) = "C"
dict.Item(4) = "D"
dict.Item(2) = "E"     'the second entry's item is overwritten

Dim k As Variant
For Each k In dict.Keys
    Debug.Print k & " - " & dict.Item(k)
Next k

覆盖方法比检查密钥.Exists但是应该理解行为要快一点。我已经使用覆盖来故​​意检索列表中具有重复键的任何键的最后一项,但这是一种特殊情况。请注意, 2 .Key并非超出原始顺序;它只是将.Item替换为后者。

如果您已添加Microsoft Scripting Runtime参考库,则可以在变量声明中使用Early Binding。这样做的好处是可以创建一个稍快的字典对象并公开其他索引枚举方法。

Dim dict As New Scripting.Dictionary

'enumerate by index position (zero-based index)
Dim i As Long
For i = 0 To dict.Count - 1
    Debug.Print dict.Keys(i) & " - " & dict.Items(i)
Next i

'enumerate as elements of an array
Dim a As Long
For a = LBound(dict.Keys) To UBound(dict.Keys)
    Debug.Print dict.Keys(a) & " - " & dict.Items(a)
Next a

fwiw,当字典.Count超过有符号整数(32,767)时,我发现这个索引枚举不可靠。

最后,键/项对可以一次删除一个,也可以一次删除。

dict.Remove 2                              'remove by key

dict.Remove dict.Keys(0)                   'remove first key/item by index position
dict.Remove dict.Keys(UBound(dict.Keys))   'remove last key/item by index position

dict.RemoveAll                             'remove all