【问题标题】:Two dimensional array as item of dictionary二维数组作为字典项
【发布时间】:2015-11-28 10:44:52
【问题描述】:

我想用一个项目的几个属性填充字典。示例:

我正在考虑将 Item 1Item 2 作为 Dictionary 键,并使用 array 来保存其属性。 我需要能够单独访问项目的每个属性,因此将它们连接为一个字符串不是一种选择。

我正在考虑类似下面的伪代码

    With Workbooks("testing macro").Sheets(test).Range("D7:G8")

     For i = 1 To .Rows.count

        items_dict.Add Key:=.Cells(i, 1).Value, _
 Item:= array(i,1)= .cells(i,2).value array(i,2)=.cells(i,3).value array(i,3).cells(i,4)

【问题讨论】:

  • 问题是什么?
  • 为什么不使用类和集合?
  • 我定义字典的方式不是工作代码。只是为了描述我认为需要发生的事情而写的。我没有使用集合,因为我需要字典的 Key 功能来选择性地提取数据。即能够获得有关我想到的特定项目的信息。
  • 您可以通过收藏来做到这一点。我将发布一个示例...

标签: arrays excel dictionary vba


【解决方案1】:

另一种方法 - 字典词典:

Option Explicit

Public Sub nestedList()
    Dim ws As Worksheet, i As Long, j As Long, x As Variant, y As Variant, z As Variant
    Dim itms As Dictionary, subItms As Dictionary   'ref to "Microsoft Scripting Runtime"

    Set ws = Worksheets("Sheet1")
    Set itms = New Dictionary

    For i = 2 To ws.UsedRange.Rows.Count

        Set subItms = New Dictionary         '<-- this should pick up a new dictionary

        For j = 2 To ws.UsedRange.Columns.Count

            '           Key: "Property 1",          Item: "A"
            subItms.Add Key:=ws.Cells(1, j).Value2, Item:=ws.Cells(i, j).Value2

        Next

        '        Key: "Item 1",              Item: subItms
        itms.Add Key:=ws.Cells(i, 1).Value2, Item:=subItms

        Set subItms = Nothing                '<-- releasing previous object

    Next
    MsgBox itms("Item 3")("Property 3")      'itms(ws.Cells(3, 1))(ws.Cells(1, 3)) = "I"
End Sub

.

它会根据行数和列数动态调整,因此无需维护

集合的好处是你可以检查键是否存在

最慢的部分是将所有项目添加到字典中,但完成后访问项目非常快

注意:字典不能有重复的键

.

编辑

如果您单步执行代码,您将能够看到以下对象:

.

如果您将 MsgBox 行替换为以下内容:

For Each x In itms.Keys
    For Each y In itms(x)
        If InStr(y, 1) > 0 Then
            Debug.Print vbNullString
            Debug.Print x & " ---> Key: '" & y & "' -> Item: '" & itms(x)(y) & "'"
        Else
            Debug.Print vbTab & vbTab & " -> Key: '" & y & "' -> Item: '" & itms(x)(y) & "'"
        End If
    Next
Next

你会得到:

Item 1 ---> Key: 'Property 1' -> Item: 'A'
         -> Key: 'Property 2' -> Item: 'B'
         -> Key: 'Property 3' -> Item: 'C'

Item 2 ---> Key: 'Property 1' -> Item: 'D'
         -> Key: 'Property 2' -> Item: 'E'
         -> Key: 'Property 3' -> Item: 'F'

Item 3 ---> Key: 'Property 1' -> Item: 'G'
         -> Key: 'Property 2' -> Item: 'H'
         -> Key: 'Property 3' -> Item: 'I'

或输入

For Each x In itms.Keys: For Each y in itms(x): Debug.Print x & " -> " & y & " -> " & itms(x)(y): Next: Next

在调试窗口中

【讨论】:

  • subItms.Add Key:=ws.Cells(1, j).Value2, Item:=ws.Cells(i, j).Value2 第一个循环设置Property 1 => A , Property 2 => B , Property 3 => C。但是,第二个设置 Property 1 => D , Property 2 => E , Property 3 => F。哪一行告诉它这些属性属于第 2 项而不是第 1 项?
  • 两个嵌套的 For 循环区分字典:外循环创建主字典,而内循环创建多个子字典。显示哪些属性属于主字典的行是itms.Add Key:=...(名为“itms”的对象是顶级字典)。我将添加结构的图像以使其更清晰
  • 在我看来,在您完成第 1 项的循环后,您将在已设置的情况下返回设置 sdict("Property 1")。对于模仿您的逻辑的代码,我还收到了一个已在使用中的密钥错误。编辑:在我看来,您创建的子词典不超过一个。
  • 这次我按原样复制粘贴了您的代码。我仍然收到错误“此键已与此集合的元素相关联”。这与我对其运行方式的理解一致,您在第二个循环期间使用相同的字典,因此您不能使用相同的 Keys,它们是属性 1、2 和 3。
  • 您在循环内使用Set subItms = New Dictionary 重置字典!那是我的问题。我没有意识到这是在循环中重置字典并允许我们在现在全新的字典上使用相同的Keys
【解决方案2】:

您也可以使用Array 函数创建一个Variant 数组来执行您最初建议的操作。如果您的数据结构变得如此复杂,那么在@sous2817 的答案中拥有一个数据模型类通常会更好。但是这种技术对于临时的、一次性的代码很有用。

Dim r As Range

For Each r In ['[testing macro.xlsx]test'!D7:G8].Rows
    ItemsDict.Add r.Cells(1).Value, Array( _
        r.Cells(2).Value, _
        r.Cells(3).Value, _
        r.Cells(4).Value)
Next

【讨论】:

  • 这是一个很好的方法。当我们在行中移动时,数组发生了什么?我们基本上是在做Array(Value1,Value2,Value3),数据只是被覆盖了吗?当我们移动到第二行时会发生什么?另外,VBA 怎么知道设置Array[1] = "Value1" 而不是调用Array[1]
  • Array(1, 2, 3) 创建一个包含元素 1,2,3 的新数组。每次通过 for 循环,都会调用 Array(),因此为每一行创建一个新数组。您可以像 Debug.Print ItemsDict("Key")(0) 那样对dict进行索引(以获取第一个元素)。不确定您的最后一个问题是什么。
  • 谢谢,感谢您回来了解其他方法。很多人在得到一些工作代码后就跑掉了。
【解决方案3】:

这里是一个使用类和集合的简单示例(基本上从示例here修改:

类很简单(类名是Employee):

Option Explicit

Private pName As String
Private pAddress As String
Private pSalary As Double

Public Property Get Name() As String
    Name = pName
End Property
Public Property Let Name(Value As String)
    pName = Value
End Property
Public Property Get Address() As String
    Address = pAddress
End Property
Public Property Let Address(Value As String)
    pAddress = Value
End Property
Public Property Get Salary() As Double
    Salary = pSalary
End Property
Public Property Let Salary(Value As Double)
    pSalary = Value
End Property

这里是测试代码:

Option Explicit

Sub test()
    Dim counter As Integer

    Dim Employees As Collection
    Dim Emp As Employee

    Dim currentEmployee As Employee


    Set Employees = New Collection

    For counter = 1 To 10
        Set Emp = New Employee

        Emp.Name = "Employee " & counter
        Emp.Address = "Address " & counter
        Emp.Salary = counter * 1000

        Employees.Add Emp, Emp.Name

    Next counter

    Set currentEmployee = Employees.Item("Employee 1")


    Debug.Print (currentEmployee.Address)

End Sub

如您所见,我正在向我的班级添加项目,指定一个键:

Employees.Add Emp, Emp.Name

然后您可以使用它直接从中提取而无需循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 2019-12-17
    • 2023-03-24
    相关资源
    最近更新 更多