Существует ли у VBA структура словаря? Как массив ключей < > value?
У VBA есть структура словаря?
Ответ 1
Да.
Установите ссылку на рабочую среду MS Scripting ("Microsoft Scripting Runtime"). В соответствии с комментарием @regjo перейдите в Tools-> "Ссылки" и поставьте галочку в поле "Время выполнения сценариев Microsoft".
Создайте экземпляр словаря, используя следующий код:
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
Ответ 2
У 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
Редактировать 24 июня 2015: Сократить Contains()
благодаря @TWiStErRob.
Редактировать 25 сентября 2015: Добавлено Err.Clear()
благодаря @scipilot.
Ответ 3
У VBA нет внутренней реализации словаря, но из VBA вы все равно можете использовать объект словаря из библиотеки сценариев MS Scripting.
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
Ответ 4
Дополнительный словарь, который полезен для хранения частоты появления.
Вне цикла:
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
Ответ 5
Создав cjrh 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
Ответ 6
Ответ 7
Сценарий времени выполнения скриптов, похоже, имеет ошибку, которая может испортить ваш дизайн на продвинутых этапах.
Если значение словаря является массивом, вы не можете обновлять значения элементов, содержащихся в массиве, через ссылку на словарь.
Ответ 8
Если по какой-либо причине вы не можете установить дополнительные функции в свой 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
Ответ 9
Все остальные уже упоминали использование версии scripting.runtime класса Dictionary. Если вы не можете использовать эту DLL, вы также можете использовать эту версию, просто добавьте ее в свой код.
https://github.com/VBA-tools/VBA-Dictionary/blob/master/Dictionary.cls
Он идентичен версии Microsoft.