首页 > 解决方案 > VBA字典没有为键赋值

问题描述

我创建了一个函数 getField,它查看电子表格的第二列和第三列,并返回一个字典,其中键是第二列,值是第三列。该函数接受一个字符串,该字符串是正在查找的字段名称,但现在我无法为键分配值。这是我指的是当前有效但值为空的行我尝试分配值失败所以我把它放在评论中向您展示我尝试过的所有内容。If InStr(data(r, 1), fieldName) > 0 Then dict(data(r, 1)) = Empty 'dict(value(r, 1))

这是其余的代码:

Public Function getField(fieldName As String)

    Dim data(), dict As Object, r As Long
    Set dict = CreateObject("Scripting.Dictionary")

    data = ThisWorkbook.Worksheets("Sheet1").UsedRange.Columns(2).value
    value = ThisWorkbook.Worksheets("Sheet1").UsedRange.Columns(3).value

    For r = 1 To UBound(data)

        If InStr(data(r, 1), fieldName) > 0 Then dict(data(r, 1)) = Empty 'dict(value(r, 1))
     Next

    data = WorksheetFunction.Transpose(dict.Keys())

    Set getField = dict

End Function

标签: excelvbadictionaryspreadsheet

解决方案


显示的代码表明您没有帮助自己。

有一个未声明的变量值。没有为函数声明返回类型。

因此,请在每个模块的开头插入 Option 显式,然后安装出色的 RubberDuck 插件并查看代码检查。这两个动作将为您在编写 VBA 宏时消除很多痛苦。

正如我在评论中提到的,代码不起作用的原因是因为这个结构。

dict(data(r, 1)) = dict(value(r, 1))

其中 dict(value(r,1)) 与 value(r,1) 作为字典值的键一起使用。这意味着第一次使用此构造时它将失败,因为字典中没有数据,因此 dict(value(r,1)) 试图访问不存在的数据。

正确的结构是

dict(data(r,1) = value(r,1)

其中要放入字典中的值 dict(data(r,1)) 是存储在索引 (r,1) 处的变量数组值中的值。

对于 scripting.dictionary 有两种添加数据的方法

Dict.add Key, Value

Dict(Key)=Value

如果字典中已经存在密钥,则上述第一个将失败。
第二种方法是一把双刃剑,如果字典中不存在该键,它将为该键创建一个条目,然后分配值。但是,如果密钥已经存在,它将覆盖分配给密钥的任何现有值。这可能是也可能不是所需的行为。

对于 add 方法,我们可以通过使用 'exists' 方法测试字典中键的存在来避免重复键发生错误。

If not dict.exists(key) then
    dict.add key,value
Else
    ' what ever action is needed in the case of duplicate keys
End if

OP 提供的代码已更新并在下面显示。

Public Function getField(fieldName As String) as Scripting.Dictioanry

    Dim myKeys As Variant   'Formerly data
    myKeys = Excel.WorksheetFunction.Transpose(ThisWorkbook.Worksheets("Sheet1").UsedRange.Columns(2).Value)

    Dim myItems As Variant  'Formerly value but not declared
    myItems = Excel.WorksheetFunction.Transpose(ThisWorkbook.Worksheets("Sheet1").UsedRange.Columns(3).Value)

    Dim myRow As Long
    Dim myDict As Scripting.Dictionary
    Set myDict = New Scripting.Dictionary
    For myRow = 0 To UBound(myKeys)

        If Not dict.Exists(myKeys(myRow)) Then

            dict.Add myKeys(myRow), myItems(myRow)

        Else

            Debug.Print "Duplicate Key found: ", myKeys(myRow)

        End If

     Next

    ' No longer required
    ' data = WorksheetFunction.Transpose(dict.Keys())

    Set getField = dict

End Function

如果我们有这样的情况,即使键重复,我们也想捕获所有值,那么我们只需创建一个字典字典

Public Function getField(fieldName As String) As Scripting.Dictioanry

    Dim myKeys As Variant   'Formerly data
    myKeys = Excel.WorksheetFunction.Transpose(ThisWorkbook.Worksheets("Sheet1").UsedRange.Columns(2).Value)

    Dim myItems As Variant  'Formerly value but not declared
    myItems = Excel.WorksheetFunction.Transpose(ThisWorkbook.Worksheets("Sheet1").UsedRange.Columns(3).Value)

    Dim myRow As Long
    Dim myDict As Scripting.Dictionary
    Set myDict = New Scripting.Dictionary
    For myRow = 0 To UBound(myKeys)

        If Not dict.Exists(myKeys(myRow)) Then

            ' add a new dictionary as the value for the key
            dict.Add myKeys(myRow), New Scripting.Dictionary

        End If

        ' now add the value to the dictionary seleted by the key
        ' we just use the current size of the sub dictionary as the index (key)
        ' for the value
        With dict.Item(myKeys(myRow))

            .Add .Count, myItem(myRow)

        End With

     Next

    Set getField = myDict

End Function

上面的代码创建了一个字典,其中分配给每个键的值本身就是一个字典。子字典收集具有相同键的所有值。您当然可以使用集合而不是子字典,因为这样就无需管理子字典的键。

要从字典中检索信息,您必须记住键检索字典

myValue = dict.item(key).item(index)

其中 Item 是用于访问字典值的默认成员(通常是隐藏的)例如上面可以写成,不太直观

myValue = myDict(key)(index)

推荐阅读