VBA是否有字典结构?像键<>值数组一样?
答案 0 :(得分:326)
是
设置对MS Scripting运行时的引用('Microsoft Scripting Runtime')。根据@ regjo的评论,转到Tools-> References并勾选“Microsoft Scripting Runtime”框。
使用以下代码创建字典实例:
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
答案 1 :(得分:169)
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()
。
答案 2 :(得分:42)
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
答案 3 :(得分:29)
另一个字典示例,可用于包含出现频率。循环外:
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
答案 4 :(得分:9)
建立cjrh's answer,我们可以建立一个不需要标签的包含功能(我不喜欢使用标签)。
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
答案 5 :(得分:6)
答案 6 :(得分:6)
脚本运行时字典似乎有一个可能在高级阶段破坏您的设计的错误。
如果字典值是数组,则无法通过对字典的引用来更新数组中包含的元素的值。
答案 7 :(得分:4)
如果由于任何原因,您无法在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
答案 8 :(得分:3)
其他所有人都已经提到过使用Scripting.runtime版本的Dictionary类。如果您无法使用此DLL,您也可以使用此版本,只需将其添加到您的代码中即可。
https://github.com/VBA-tools/VBA-Dictionary/blob/master/Dictionary.cls
它与Microsoft的版本相同。
答案 9 :(得分:1)
您可以通过 HashTable
访问非本地 System.Collections.HashTable
。
表示基于以下条件组织的键/值对的集合 密钥的哈希码。
不确定您是否想在 Scripting.Dictionary
上使用它,但为了完整起见,在此处添加。如果有一些兴趣,您可以查看这些方法,例如Clone, CopyTo
示例:
Option Explicit
Public Sub UsingHashTable()
Dim h As Object
Set h = CreateObject("System.Collections.HashTable")
h.Add "A", 1
' h.Add "A", 1 ''<< Will throw duplicate key error
h.Add "B", 2
h("B") = 2
Dim keys As mscorlib.IEnumerable 'Need to cast in order to enumerate 'https://stackoverflow.com/a/56705428/6241235
Set keys = h.keys
Dim k As Variant
For Each k In keys
Debug.Print k, h(k) 'outputs the key and its associated value
Next
End Sub
@MathieuGuindon 的这个 answer 提供了大量关于 HashTable 的细节,以及为什么有必要使用 mscorlib.IEnumerable
(对 mscorlib 的早期绑定引用)来枚举键:值对。>
答案 10 :(得分:0)
VBA可以使用Scripting.Runtime
的字典结构。
它的实现实际上是一个幻想-仅需执行myDict(x) = y
,它就会检查字典中是否有键x
如果没有,它甚至会创建它。如果在那里,它将使用它。
对于“在幕后”执行的这一额外步骤,它不会“大喊”或“抱怨”。当然,您可以显式检查Dictionary.Exists(key)
是否存在密钥。因此,这5行:
If myDict.exists("B") Then
myDict("B") = myDict("B") + i * 3
Else
myDict.Add "B", i * 3
End If
与此1个底线相同-myDict("B") = myDict("B") + i * 3
。检查一下:
Sub TestMe()
Dim myDict As Object, i As Long, myKey As Variant
Set myDict = CreateObject("Scripting.Dictionary")
For i = 1 To 3
Debug.Print myDict.Exists("A")
myDict("A") = myDict("A") + i
myDict("B") = myDict("B") + 5
Next i
For Each myKey In myDict.keys
Debug.Print myKey; myDict(myKey)
Next myKey
End Sub