【问题标题】:VBA: How to build up nested dictionaries in a loop (ByVal?)VBA:如何在循环中构建嵌套字典(ByVal?)
【发布时间】:2019-12-08 22:51:44
【问题描述】:

我正在从 Excel 电子表格中导出多个 INI 文件,其中一行表示一个 INI 文件,INI 部分和键是列。到目前为止,这工作得很好,除了似乎 VBA 正在传递字典 ByRef (?),但让我解释一下:

Excel 电子表格如下所示:

       |       section 1       |   section 2   |  section 3  | ...
       | key1  | key2  | key3  | key4  | key3  |  ...
name 1 | value | value | value | value | value |  ...
name 2 | value | value | value | value | value |  ...
...

我从电子表格中动态获取所有 INI 部分、键和值,这就是为什么我决定不构建类模块而是设置具有 3 个嵌套字典的字典结构,如下所示:

innerdict:保存一个部分的键/值对
middledict:保存部分名称和带有键/值对的内部字典
outerdict:保存行用 middledict 命名

下面的简化代码应该可以解释我的情况:

Set outerDict = New Scripting.Dictionary
Set middleDict = New Scripting.Dictionary
Set innerDict = New Scripting.Dictionary

For row = 3 to 10
For col = 1 to 5
  key = Cells(a,b).Value
  value = Cells(x,y).Value
  innerdict.Add key, value

  If nextSectionGroup Then
    middledict.Add sectionName, innerdict
    innerdict.RemoveAll
  End If
Next col

outerdict.Add linename, middledict
middledict.RemoveAll

Next row

一句话:
从第一个值行开始,我遍历列,填充内部字典中的键/值对,直到我到达一个部分的末尾。

然后我(想要)innerdict 复制到middledict 中,然后删除innerdict 的内容,以便下一节使用。如果我打到整行的末尾,我将middledict 复制到outerdict 并删除middledict 的内容,以便它可以用于下一行。

但是运行上述代码后,middledictinnerdict 无法通过outerdict 访问,看起来它们只是空的。如果我删除那些 .RemoveAll 语句,代码可以正常工作,但会用错误的内容填充字典。

在我看来,dict.Add 不会将内容复制到父 dict,而是进行引用。这可以解释为什么在.RemoveAll 之后内容为空。

但是如何解决呢,有人能指点一下吗?

谢谢。

【问题讨论】:

  • 无论ByVal 还是ByRef,在赋值或作为参数传递时,引用类型的实例都不会被复制。类是引用类型。字典是一个类。
  • 因为你想克隆一个字典,这是一个不受你控制的类,你需要手动克隆它(创建一个新字典并添加原始字典中的所有键和值) .请注意,这将创建一个浅拷贝,即字典将不同,但如果字典中包含的值本身是引用类型,则两个字典将引用相同的数据实例,您需要克隆他们也是。
  • .RemoveAll 替换为Set ... = New Scripting.Dictionary 以创建新引用。尽管您应该避免嵌套字典。例如,如果您的目标是按名称、部分、键获取值,则将所有值存储在一个字典中:dict.Add name & "|" & section & "|" & key, Value
  • 当然,无论您是否销毁对象都会有所不同。问题是,无论哪种方式,你都是not destroying themmiddledict 保留对您所有 innerdicts 的引用,否则您以后如何检索它们?

标签: excel vba dictionary nested


【解决方案1】:

了解您想如何处理数据将对解决方案产生重大影响。如果您只想检索单个数据项,FlorentB 对分隔键的建议很有吸引力。如果您想在这些列表中迭代数据,那么嵌套字典可能是您的最佳选择。

对于嵌套字典,如您所见,存储了对该对象的引用。因此,您需要为每个嵌套字典创建一个新的字典实例。那么,一些骨架代码将如下所示:

Dim v As Variant
Dim r As Long, c As Long
Dim nameDic As Dictionary, secDic As Dictionary, valDic As Dictionary

'Find area of data.
With Sheet1
    r = .Cells(.Rows.Count, 1).End(xlUp).Row
    c = .Cells(2, .Columns.Count).End(xlToLeft).Column
    v = .Range(.Cells(1, 1), .Cells(r, c)).Value2
End With

'Populate dictionaries.
Set nameDic = New Dictionary
For r = 3 To UBound(v, 1)
    Set secDic = New Dictionary
    nameDic.Add v(r, 1), secDic
    For c = 2 To UBound(v, 2)
        If Not IsEmpty(v(1, c)) Then
            'It's a new section.
            Set valDic = New Dictionary
            secDic.Add v(1, c), valDic
        End If
        valDic.Add v(2, c), v(r, c)
    Next
Next

'Single data items can be retrieved like so:
Debug.Print nameDic("name 2")("section 2")("key 4")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-16
    • 2021-05-30
    • 2023-03-12
    • 2017-07-22
    • 2022-06-15
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多