【问题标题】:Looping through a Scripting.Dictionary using index/item number使用索引/项目编号循环遍历 Scripting.Dictionary
【发布时间】:2012-07-03 00:51:10
【问题描述】:

类似于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) 行上收到 object expected error 时,这让我措手不及。

郑重声明,我知道我可以这样做:

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

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

【问题讨论】:

  • @assylias 我确实在文档.Item(Key) 中看到了这一点,但我也看到了.Key(Key),虽然我不确定如何使用Key 方法...有没有办法按项目编号迭代?

标签: vba dictionary


【解决方案1】:

根据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

【讨论】:

  • 我遵循这一点,但是有没有办法通过索引/项目编号迭代/读取? 如果你问我,这似乎是一个愚蠢的实现。 ;-)
  • 有了这些信息,我已将问题更改为不包含“错误”措辞。
【解决方案2】:

添加到 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 方法。较短的语法最适合从字典中按数字提取单个项目。

【讨论】:

    【解决方案3】:

    使用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
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2015-03-06
        • 2017-09-10
        • 1970-01-01
        • 1970-01-01
        • 2013-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多