Таблиця хеш-масивів / асоціативний масив у VBA


90

Здається, я не можу знайти документацію, що пояснює, як створити хеш-таблицю або асоціативний масив у VBA. Це взагалі можливо?

Чи можете ви зробити посилання на статтю чи ще краще опублікувати код?



Відповіді:


109

Я думаю, ви шукаєте об’єкт «Словник», який можна знайти в бібліотеці виконання сценаріїв Microsoft. (Додайте посилання на свій проект із меню Інструменти ... Посилання у VBE.)

Це майже працює з будь-яким простим значенням, яке може вміститися у варіанті (ключі не можуть бути масивами, і намагатися зробити їх об’єктами не має особливого сенсу. Див. Коментар від @Nile нижче.):

Dim d As dictionary
Set d = New dictionary

d("x") = 42
d(42) = "forty-two"
d(CVErr(xlErrValue)) = "Excel #VALUE!"
Set d(101) = New Collection

Ви також можете використовувати об'єкт колекції VBA, якщо ваші потреби простіші і вам потрібні лише рядкові ключі.

Я не знаю, чи насправді щось хешує на чомусь, тому, можливо, ви захочете копати далі, якщо вам потрібна продуктивність, схожа на хеш-таблицю. (EDIT: Scripting. Dictionary використовує внутрішню хеш-таблицю .)


так - словник - це відповідь. Відповідь я знайшов і на цьому сайті. stackoverflow.com/questions/915317 / ...
user158017

2
Це досить гарна відповідь: але ключі ніколи не є об’єктами - насправді відбувається те, що властивість об’єкта за замовчуванням відтворюється як рядок і використовується як ключ. Це не працює, якщо для об’єкта не визначено властивості за замовчуванням (зазвичай „ім’я“).
Найджел Хеффернан

@ Ніл, дякую. Я бачу, що ви справді праві. Також схоже на те, що якщо об'єкт не має властивості за замовчуванням, то відповідним ключем словника є Empty. Відповідь я відредагував.
jtolle

Кілька структур даних пояснив тут- analystcave.com / ... цій пост показує , як використовувати .next HashTables в Excel VBA- stackoverflow.com/questions/8677949 / ...
Johny , чому

надрукована помилка вище: .NET, а не .NEXT.
johny чому


7

Спробуйте використати об’єкт словника або об’єкт колекції.

http://visualbasic.ittoolbox.com/documents/dictionary-object-vs-collection-object-12196


1
Наведене посилання більше не працює. Зміст таким, яким він був на момент оригінальної публікації, можна переглянути тут: web.archive.org/web/20090729034340/http://…
Пол ван Левен

6

Ось і ми ... просто скопіюйте код в модуль, він готовий до використання

Private Type hashtable
    key As Variant
    value As Variant
End Type

Private GetErrMsg As String

Private Function CreateHashTable(htable() As hashtable) As Boolean
    GetErrMsg = ""
    On Error GoTo CreateErr
        ReDim htable(0)
        CreateHashTable = True
    Exit Function

CreateErr:
    CreateHashTable = False
    GetErrMsg = Err.Description
End Function

Private Function AddValue(htable() As hashtable, key As Variant, value As Variant) As Long
    GetErrMsg = ""
    On Error GoTo AddErr
        Dim idx As Long
        idx = UBound(htable) + 1

        Dim htVal As hashtable
        htVal.key = key
        htVal.value = value

        Dim i As Long
        For i = 1 To UBound(htable)
            If htable(i).key = key Then Err.Raise 9999, , "Key [" & CStr(key) & "] is not unique"
        Next i

        ReDim Preserve htable(idx)

        htable(idx) = htVal
        AddValue = idx
    Exit Function

AddErr:
    AddValue = 0
    GetErrMsg = Err.Description
End Function

Private Function RemoveValue(htable() As hashtable, key As Variant) As Boolean
    GetErrMsg = ""
    On Error GoTo RemoveErr

        Dim i As Long, idx As Long
        Dim htTemp() As hashtable
        idx = 0

        For i = 1 To UBound(htable)
            If htable(i).key <> key And IsEmpty(htable(i).key) = False Then
                ReDim Preserve htTemp(idx)
                AddValue htTemp, htable(i).key, htable(i).value
                idx = idx + 1
            End If
        Next i

        If UBound(htable) = UBound(htTemp) Then Err.Raise 9998, , "Key [" & CStr(key) & "] not found"

        htable = htTemp
        RemoveValue = True
    Exit Function

RemoveErr:
    RemoveValue = False
    GetErrMsg = Err.Description
End Function

Private Function GetValue(htable() As hashtable, key As Variant) As Variant
    GetErrMsg = ""
    On Error GoTo GetValueErr
        Dim found As Boolean
        found = False

        For i = 1 To UBound(htable)
            If htable(i).key = key And IsEmpty(htable(i).key) = False Then
                GetValue = htable(i).value
                Exit Function
            End If
        Next i
        Err.Raise 9997, , "Key [" & CStr(key) & "] not found"

    Exit Function

GetValueErr:
    GetValue = ""
    GetErrMsg = Err.Description
End Function

Private Function GetValueCount(htable() As hashtable) As Long
    GetErrMsg = ""
    On Error GoTo GetValueCountErr
        GetValueCount = UBound(htable)
    Exit Function

GetValueCountErr:
    GetValueCount = 0
    GetErrMsg = Err.Description
End Function

Щоб використовувати у своєму додатку VB (A):

Public Sub Test()
    Dim hashtbl() As hashtable
    Debug.Print "Create Hashtable: " & CreateHashTable(hashtbl)
    Debug.Print ""
    Debug.Print "ID Test   Add V1: " & AddValue(hashtbl, "Hallo_0", "Testwert 0")
    Debug.Print "ID Test   Add V2: " & AddValue(hashtbl, "Hallo_0", "Testwert 0")
    Debug.Print "ID Test 1 Add V1: " & AddValue(hashtbl, "Hallo.1", "Testwert 1")
    Debug.Print "ID Test 2 Add V1: " & AddValue(hashtbl, "Hallo-2", "Testwert 2")
    Debug.Print "ID Test 3 Add V1: " & AddValue(hashtbl, "Hallo 3", "Testwert 3")
    Debug.Print ""
    Debug.Print "Test 1 Removed V1: " & RemoveValue(hashtbl, "Hallo_1")
    Debug.Print "Test 1 Removed V2: " & RemoveValue(hashtbl, "Hallo_1")
    Debug.Print "Test 2 Removed V1: " & RemoveValue(hashtbl, "Hallo-2")
    Debug.Print ""
    Debug.Print "Value Test 3: " & CStr(GetValue(hashtbl, "Hallo 3"))
    Debug.Print "Value Test 1: " & CStr(GetValue(hashtbl, "Hallo_1"))
    Debug.Print ""
    Debug.Print "Hashtable Content:"

    For i = 1 To UBound(hashtbl)
        Debug.Print CStr(i) & ": " & CStr(hashtbl(i).key) & " - " & CStr(hashtbl(i).value)
    Next i

    Debug.Print ""
    Debug.Print "Count: " & CStr(GetValueCount(hashtbl))
End Sub

18
Я не збираюся голосувати проти абсолютно нового користувача, який публікує код, але зазвичай називаючи щось "хеш-таблицею" означає, що основна реалізація насправді є хеш-таблицею! У вас тут є асоціативний масив, реалізований за допомогою звичайного масиву плюс лінійний пошук. Дивіться тут для різниці: en.wikipedia.org/wiki/Hash_table
jtolle

7
Справді. Сенс хеш-таблиці полягає у тому, що "хешування" ключа веде до розташування його значення в базовому сховищі (або принаймні досить близько, у випадку дозволених дублікатів ключів), таким чином усуваючи необхідність у потенційно дорогому пошуку.
Cor_Blimey

3
Дуже повільно для великих хештегов. Додавання 17000 записів займає більше 15 секунд. Я можу додати 500 000 за 6 секунд за допомогою словника. 500 000 менш ніж за 3 секунди за допомогою хеш-таблиці mscorlib.
Крістофер Томас Никодим
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.