【问题标题】:Change value of an item in a collection in a dictionary更改字典中集合中项目的值
【发布时间】:2015-11-17 18:25:39
【问题描述】:

我正在尝试创建一个字典,其中包含每个键的集合。这样做的原因是我想稍后从同一个键中检索多个值。在此示例中,我希望获得唯一键的总值 (val) 以及出现次数 (n):

sub update()
Dim dict As Dictionary
Dim coll As Collection
Set dict = New Dictionary
Set coll = New Collection

coll.Add 100, "val"
coll.Add 3, "n"
dict.Add "coll", coll

Debug.Print dict.item("coll")("val")
Debug.Print dict.item("coll")("n")

到目前为止,这工作正常,当我尝试更新集合中的值时会出现问题(对象不支持这个):

dict.item("coll")("val") = dict.item("coll")("val") + 100

我尝试了什么:

如果我使用数组而不是集合,则不会出现错误,但值不会改变。 它仅在我将集合读出到变量、更改值、创建新集合、从字典中删除旧集合并添加新集合时才有效。

有没有办法像我上面的方法一样在一行中做到这一点? 我也很乐意为该任务提供替代解决方案。

【问题讨论】:

  • 对于类似的问题,我使用了用户定义的对象(类),然后将类对象添加到集合中。 (UDO 可以有多个属性;甚至可以将集合作为其属性之一)。关键是一些唯一的字符串。您可能可以对 Dictionary 对象做类似的事情,就像对 Collection 一样,但我没有使用过。
  • 感谢您的建议!不幸的是我还没有真正进入UDO,必须仔细看看它..

标签: excel vba dictionary collections


【解决方案1】:

一旦您将一个项目添加到集合中,您就无法轻易更改它。这样的表达:

coll("n") = 5

将导致运行时错误“424”:需要对象

您可以通过下面的简单示例自行检查:

Sub testCol()
    Dim col As New VBA.Collection
    Call col.Add(1, "a")

    col("a") = 2  '<-- this line will cause Run-time error '424'

End Sub

在给定集合中更改分配给指定键的值的唯一方法是删除该值并添加具有相同键的另一个值。

下面是一个简单的例子,如何将分配给带有键 [a] 的集合的值从 1 更改为 2:

Sub testCol()
    Dim col As New VBA.Collection
    With col
        Call .Add(1, "a")
        Call .Remove("a")
        Call .Add(2, "a")
    End With
End Sub

以下是您修改的代码,以便您更改分配给集合中给定键的值:

Sub update()
    Dim dict As Dictionary
    Dim coll As Collection
    Set dict = New Dictionary
    Set coll = New Collection

    coll.Add 100, "val"
    coll.Add 3, "n"
    dict.Add "coll", coll

    Debug.Print dict.Item("coll")("val")
    Debug.Print dict.Item("coll")("n")
    'This works fine so far, the problem occurs when I try to update the value in the collection (object doesn't support this):

    Dim newValue As Variant
    With dict.Item("coll")
        newValue = .Item("val") + 100
        On Error Resume Next '<---- [On Error Resume Next] to avoid error if there is no such key in this collection yet.
        Call .Remove("val")
        On Error GoTo 0
        Call .Add(newValue, "val")
    End With

End Sub

【讨论】:

  • 非常感谢!这是一个非常明确的解释。现在我在一个单独的函数中进行更新,这使得主代码更具可读性。
【解决方案2】:

也许不优雅,但也许你可以写一个子来通过一个键更新一个集合:

Sub UpdateCol(ByRef C As Collection, k As Variant, v As Variant)
    On Error Resume Next
    C.Remove k
    On Error GoTo 0
    C.Add v, k
End Sub

这样使用:

Sub Update()
    Dim dict As Dictionary
    Dim coll As Collection
    Set dict = New Dictionary
    Set coll = New Collection

    coll.Add 100, "val"
    coll.Add 3, "n"
    dict.Add "coll", coll

    Debug.Print dict.Item("coll")("val")
    Debug.Print dict.Item("coll")("n")

    UpdateCol dict.Item("coll"), "val", dict.Item("coll")("val") + 100
    Debug.Print dict.Item("coll")("val")
End Sub

按预期输出:

100 
3 
200 

【讨论】:

    【解决方案3】:

    这是一种使用用户定义对象(类)的方法。希望您可以根据自己的问题调整它。

    重命名类模块 cMyStuff 或其他有意义的名称。

    类模块

    Option Explicit
    Private pTotalVal As Long
    Private pCounter As Long
    
    Public Property Get TotalVal() As Long
        TotalVal = pTotalVal
    End Property
    Public Property Let TotalVal(Value As Long)
        pTotalVal = Value
    End Property
    
    Public Property Get Counter() As Long
        Counter = pCounter
    End Property
    Public Property Let Counter(Value As Long)
        pCounter = Value
    End Property
    

    常规模块

    Option Explicit
    Sub Update()
        Dim cMS As cMyStuff, dMS As Dictionary
        Dim I As Long
    
    Set dMS = New Dictionary
    For I = 1 To 3
        Set cMS = New cMyStuff
        With cMS
            .Counter = 1
            .TotalVal = I * 10
            If Not dMS.Exists("coll") Then
                dMS.Add "coll", cMS
            Else
                With dMS("coll")
                    .TotalVal = .TotalVal + cMS.TotalVal
                    .Counter = .Counter + 1
                End With
            End If
        End With
    Next I
    
    With dMS("coll")
        Debug.Print "Total Value", .TotalVal
        Debug.Print "Counter", .Counter
    End With
    
    End Sub
    

    立即窗口中的结果

    Total Value    60 
    Counter        3 
    

    【讨论】:

    • 非常感谢!同上..我必须先进入UDO,到目前为止从未使用过Class Module。看起来有很多可能性。
    猜你喜欢
    • 2012-08-08
    • 1970-01-01
    • 2013-02-25
    • 1970-01-01
    • 2011-07-28
    • 2010-11-04
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    相关资源
    最近更新 更多