首页 文章

VBA有词典结构吗?

提问于
浏览
236

VBA有字典结构吗?像键<>值数组?

9 回答

  • 28

    是 .

    设置对MS Scripting运行时的引用('Microsoft Scripting Runtime') . 根据@ regjo的评论,转到Tools-> References并勾选“Microsoft Scripting Runtime”框 .

    References Window

    使用以下代码创建字典实例:

    Set dict = CreateObject("Scripting.Dictionary")
    

    要么

    Dim dict As New Scripting.Dictionary
    

    使用示例:

    If Not dict.Exists(key) Then 
        dict.Add key, value
    End If
    

    完成使用后,不要忘记将字典设置为 Nothing .

    Set dict = Nothing
    
  • 9

    VBA有集合对象:

    Dim c As Collection
        Set c = New Collection
        c.Add "Data1", "Key1"
        c.Add "Data2", "Key2"
        c.Add "Data3", "Key3"
        'Insert data via key into cell A1
        Range("A1").Value = c.Item("Key2")
    

    Collection 对象使用哈希执行基于键的查找,因此它很快 .


    您可以使用 Contains() 函数来检查特定集合是否包含密钥:

    Public Function Contains(col As Collection, key As Variant) As Boolean
        On Error Resume Next
        col(key) ' Just try it. If it fails, Err.Number will be nonzero.
        Contains = (Err.Number = 0)
        Err.Clear
    End Function
    

    编辑2015年6月24日:感谢@TWiStErRob缩短 Contains() .

    编辑2015年9月25日:感谢@scipilot添加 Err.Clear() .

  • 6

    VBA没有字典的内部实现,但是从VBA仍然可以使用MS Scripting Runtime Library中的字典对象 .

    Dim d
    Set d = CreateObject("Scripting.Dictionary")
    d.Add "a", "aaa"
    d.Add "b", "bbb"
    d.Add "c", "ccc"
    
    If d.Exists("c") Then
        MsgBox d("c")
    End If
    
  • 305

    一个附加的字典示例,可用于包含出现的频率 .

    循环之外:

    Dim dict As New Scripting.dictionary
    Dim MyVar as String
    

    在一个循环中:

    'dictionary
    If dict.Exists(MyVar) Then
        dict.Item(MyVar) = dict.Item(MyVar) + 1 'increment
    Else
        dict.Item(MyVar) = 1 'set as 1st occurence
    End If
    

    检查频率:

    Dim i As Integer
    For i = 0 To dict.Count - 1 ' lower index 0 (instead of 1)
        Debug.Print dict.Items(i) & " " & dict.Keys(i)
    Next i
    
  • 39

    Build cjrh's answer,我们可以构建一个不需要标签的Contains函数(我不喜欢使用标签) .

    Public Function Contains(Col As Collection, Key As String) As Boolean
        Contains = True
        On Error Resume Next
            err.Clear
            Col (Key)
            If err.Number <> 0 Then
                Contains = False
                err.Clear
            End If
        On Error GoTo 0
    End Function
    

    对于我的一个项目,我编写了一组辅助函数,使 Collection 表现得更像 Dictionary . 它仍然允许递归集合 . 您会注意到Key始终是第一位的,因为它是强制性的,在我的实现中更有意义 . 我也只使用了 String 键 . 如果你愿意,你可以改回来 .

    设置

    我将其重命名为set,因为它将覆盖旧值 .

    Private Sub cSet(ByRef Col As Collection, Key As String, Item As Variant)
        If (cHas(Col, Key)) Then Col.Remove Key
        Col.Add Array(Key, Item), Key
    End Sub
    

    得到

    err 东西用于对象,因为你可以使用 set 传递对象而不使用变量 . 我想你可以检查一下它是不是一个物体,但是时间紧迫 .

    Private Function cGet(ByRef Col As Collection, Key As String) As Variant
        If Not cHas(Col, Key) Then Exit Function
        On Error Resume Next
            err.Clear
            Set cGet = Col(Key)(1)
            If err.Number = 13 Then
                err.Clear
                cGet = Col(Key)(1)
            End If
        On Error GoTo 0
        If err.Number <> 0 Then Call err.raise(err.Number, err.Source, err.Description, err.HelpFile, err.HelpContext)
    End Function
    

    这篇帖子的原因......

    Public Function cHas(Col As Collection, Key As String) As Boolean
        cHas = True
        On Error Resume Next
            err.Clear
            Col (Key)
            If err.Number <> 0 Then
                cHas = False
                err.Clear
            End If
        On Error GoTo 0
    End Function
    

    删除

    如果它不存在则不抛出 . 只是确保它已被删除 .

    Private Sub cRemove(ByRef Col As Collection, Key As String)
        If cHas(Col, Key) Then Col.Remove Key
    End Sub
    

    获取一系列密钥 .

    Private Function cKeys(ByRef Col As Collection) As String()
        Dim Initialized As Boolean
        Dim Keys() As String
    
        For Each Item In Col
            If Not Initialized Then
                ReDim Preserve Keys(0)
                Keys(UBound(Keys)) = Item(0)
                Initialized = True
            Else
                ReDim Preserve Keys(UBound(Keys) + 1)
                Keys(UBound(Keys)) = Item(0)
            End If
        Next Item
    
        cKeys = Keys
    End Function
    
  • 3

    脚本运行时字典似乎有一个可能在高级阶段破坏您的设计的错误 .

    如果字典值是数组,则无法通过对字典的引用来更新数组中包含的元素的值 .

  • 4

    是 . 对于VB6,VBA(Excel)和VB.NET

  • 162

    如果由于任何原因,您无法在Excel中安装或不想安装其他功能,您也可以使用数组,至少对于简单的问题 . 作为WhatIsCapital,你把国家的名字和功能归还给你的资本 .

    Sub arrays()
    Dim WhatIsCapital As String, Country As Array, Capital As Array, Answer As String
    
    WhatIsCapital = "Sweden"
    
    Country = Array("UK", "Sweden", "Germany", "France")
    Capital = Array("London", "Stockholm", "Berlin", "Paris")
    
    For i = 0 To 10
        If WhatIsCapital = Country(i) Then Answer = Capital(i)
    Next i
    
    Debug.Print Answer
    
    End Sub
    
  • 6

    所有其他人已经提到过使用Scripting.runtime版本的Dictionary类 . 如果您无法使用此DLL,您也可以使用此版本,只需将其添加到您的代码中即可 .

    https://github.com/VBA-tools/VBA-Dictionary/blob/master/Dictionary.cls

    它与Microsoft的版本相同 .

相关问题