Czy VBA ma strukturę słownika? Podobnie jak tablica wartości klucza <>?
Czy VBA ma strukturę słownika? Podobnie jak tablica wartości klucza <>?
Odpowiedzi:
Tak.
Ustaw odwołanie do środowiska wykonawczego MS Scripting („Microsoft Scripting Runtime”). Zgodnie z komentarzem @ regjo, przejdź do Narzędzia-> Referencje i zaznacz pole „Microsoft Scripting Runtime”.
Utwórz instancję słownika za pomocą poniższego kodu:
Set dict = CreateObject("Scripting.Dictionary")
lub
Dim dict As New Scripting.Dictionary
Przykład zastosowania:
If Not dict.Exists(key) Then
dict.Add key, value
End If
Nie zapomnij ustawić słownika, Nothing
kiedy skończysz go używać.
Set dict = Nothing
keyed
.
Dim dict As New Scripting.Dictionary
bez odniesienia. Bez odwołania musisz użyć metody późnego wiązania CreateObject
w celu utworzenia tego obiektu.
VBA ma obiekt kolekcji:
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")
Na Collection
obiekt wykonuje kluczowych oparte wyszukiwań za pomocą skrótu, dlatego szybko.
Możesz użyć Contains()
funkcji, aby sprawdzić, czy dana kolekcja zawiera klucz:
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
Edytuj 24 czerwca 2015 : Krótsze Contains()
dzięki @TWiStErRob.
Edytuj 25 września 2015 : Dodano Err.Clear()
dzięki @scipilot.
ContainsKey
; ktoś czytający tylko wywołanie może pomylić je ze sprawdzeniem, czy zawiera ono określoną wartość.
Dodatkowy przykład słownika, który jest przydatny do ograniczenia częstotliwości występowania.
Poza pętlą:
Dim dict As New Scripting.dictionary
Dim MyVar as String
W pętli:
'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
Aby sprawdzić częstotliwość:
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
Opierając się na odpowiedzi cjrh , możemy zbudować funkcję Contains nie wymagającą żadnych etykiet (nie lubię używać etykiet).
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
Dla mojego projektu napisałem zestaw funkcji pomocniczych, aby Collection
bardziej zachowywać się jak Dictionary
. Nadal pozwala na kolekcje rekurencyjne. Zauważysz, że klucz zawsze jest najważniejszy, ponieważ był obowiązkowy i miał sens w mojej implementacji. Użyłem także tylko String
kluczy. Możesz to zmienić, jeśli chcesz.
Zmieniłem nazwę, aby ustawić, ponieważ spowoduje to zastąpienie starych wartości.
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
Rzeczy jest dla obiektów gdyż przechodzą obiekty przy użyciu set
i bez zmiennych. Myślę, że możesz po prostu sprawdzić, czy to obiekt, ale byłem zmuszony do czasu.
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
Powód tego postu ...
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
Nie rzuca, jeśli nie istnieje. Tylko upewnia się, że został usunięty.
Private Sub cRemove(ByRef Col As Collection, Key As String)
If cHas(Col, Key) Then Col.Remove Key
End Sub
Zdobądź tablicę kluczy.
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
Jeśli z jakiegoś powodu nie możesz zainstalować dodatkowych funkcji w programie Excel lub nie chcesz, możesz również użyć tablic, przynajmniej w przypadku prostych problemów. Jako WhatIsCapital podajesz nazwę kraju, a funkcja zwraca ci swój kapitał.
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
Dim
słowa kluczowego Country
i Capital
musi zostać zadeklarowana jako Warianty ze względu na użycie Array()
, i
powinna zostać zadeklarowana (i musi być Option Explicit
ustawiona, jeśli jest ustawiona), a licznik pętli wyrzuci błąd spoza zakresu - bezpieczniej użyj UBound(Country)
dla To
wartości. Warto również zauważyć, że chociaż Array()
funkcja jest przydatnym skrótem, nie jest to standardowy sposób deklarowania tablic w VBA.
Wszyscy pozostali wspominali już o użyciu skryptu.runtime w wersji klasy Dictionary. Jeśli nie możesz użyć tej biblioteki DLL, możesz również użyć tej wersji, po prostu dodaj ją do swojego kodu.
https://github.com/VBA-tools/VBA-Dictionary/blob/master/Dictionary.cls
Jest identyczny z wersją Microsoftu.