Имеет ли VBA структуру словаря?


имеет ли VBA структуру словаря? Как ключ массив значений?

9 230

9 ответов:

да.

установите ссылку на MS Scripting runtime ('Microsoft Scripting Runtime'). В соответствии с комментарием @regjo, перейдите в сервис- > ссылки и отметьте поле для "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 

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")

The 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.

VBA не имеет внутренней реализации словаря, но из VBA вы все еще можете использовать объект dictionary из библиотеки MS Scripting Runtime.

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

дополнительный пример словаря, который полезен для содержания частоты возникновения.

за пределами петли:

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

здание с ответ cjrh, мы можем построить функцию 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. Он по-прежнему позволяет рекурсивные коллекции. Вы заметите, что ключ всегда приходит первым, потому что он был обязательным и больше смысла в моей реализации. Я также использовал только 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

Get

The 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

в словаре времени выполнения сценариев, похоже, есть ошибка, которая может разрушить ваш дизайн на продвинутых этапах.

Если значение словаря является массивом, вы не можете обновить значения элементов, содержащихся в массиве, с помощью ссылки на словарь.

да. Ибо VB6, VBA (Excel), и VB.NET

Если по какой-либо причине вы не можете установить дополнительные функции в 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

все остальные уже упоминали об использовании сценариев.версия времени выполнения класса словаря. Если вы не можете использовать эту DLL, вы также можете использовать эту версию, просто добавьте его в свой код.

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

он идентичен версии Microsoft.