VBA-DictionaryでWin/mac共通のVBAコードを書く


連想配列といわれるDictionaryオブジェクトはキーと値(key-value)でデータを管理し、キーによって一元性が担保されていたり、データのカウントや設定/取得のメソッドが充実しているとても便利なオブジェクトであることは、皆さんご存じのことだろう。だがVBAで用意されているDictionaryクラスはmacでは使えない(Microsoftさんの意図は分からない。。)今回紹介する「VBA-Dictionary」でDictionaryクラスを上書き(mac的には新設)することで、WinでもmacでもDictionaryオブジェクトを同様に使うことができるようになる。Win/mac両方で動くツールを作ることをモットーとしている私としては、これを紹介せずにはいられない。

まずは公式ReadmeのGoogle翻訳から。


VBA-Dictionary

VBA-Dictionary is a drop-in replacement for the useful and powerful Scripting.Dictionary so that it can be used with both Mac and Windows. It is designed to be a precise replacement to Scripting.Dictionary including Item as the default property (Dict("A") = Dict.Item("A")), matching error codes, and matching methods and properties. If you find any implementation differences between Scripting.Dictionary and VBA-Dictionary, please create an issue.

VBA-Dictionaryは、MacとWindowsの両方で使用できるように、便利で強力な Scripting.Dictionaryに代わるドロップインです。 これは、デフォルトのプロパティとして Itemを含むScripting.DictionaryDict(" A ")= Dict.Item(" A "))、一致するエラーコード、および一致するメソッドと正確に置き換えられるように設計されています。 プロパティ。 Scripting.DictionaryとVBA-Dictionaryの実装に違いがある場合は、問題を作成してください。


Installing

Download the latest release, unzip, and import Dictionary.cls into your VBA project.

最新リリースをダウンロードし、解凍して、VBAプロジェクトに「Dictionary.cls」をインポートします。

Example

VB.net
' (Works exactly like Scripting.Dictionary)
' (Scripting.Dictionaryとまったく同じように機能します)
Dim Dict As New Dictionary
Dict.CompareMode = CompareMethod.TextCompare

Dict("A") ' -> Empty
Dict("A") = 123
Dict("A") ' -> = Dict.Item("A") = 123
Dict.Exists "A" ' -> True

Dict.Add "A", 456
' -> Throws 457: This key is already associated with an element of this collection
' -> Throws 457: このキーはすでにこのコレクションの要素に関連付けられています
' Both Set and Let work
' SetとLetの両方
Set Dict("B") = New Dictionary
Dict("B").Add "Inner", "Value"
Dict("B")("Inner") ' -> "Value"

UBound(Dict.Keys) ' -> 1
UBound(Dict.Items) ' -> 1

' Rename key
' キーの削除
Dict.Key("B") = "C"
Dict.Exists "B" ' -> False
Dict("C")("Inner") ' -> "Value"

' Trying to remove non-existant key throws 32811
' 存在しないキーを削除しようとすると、32811がスローされます
Dict.Remove "B"
' -> Throws 32811: Application-defined or object-defined error

' Trying to change CompareMode when there are items in the Dictionary throws 5
' ディクショナリにアイテムがあるときにCompareModeを変更しようとすると、5がスローされます。
Dict.CompareMode = CompareMethod.BinaryCompare
' -> Throws 5: Invalid procedure call or argument

Dict.Remove "A"
Dict.RemoveAll

Dict.Exists "A" ' -> False
Dict("C") ' -> Empty

検証

Exampleでは紹介されていない、だがとても重要なFor..Eachで使えるかを検証するため、以下のコードをWin/mac両方のExcelで実行した。

Public Sub test()

    Dim Dict As New Dictionary
    Dict.CompareMode = CompareMethod.TextCompare

    Dict.Add "1", "a"
    Dict.Add "2", "b"
    Dict.Add "3", "c"
    Dict.Add "4", "d"
    Dict.Add "5", "e"
    Dict.Add "6", "f"

    Dim key As Variant
    For Each key In Dict.Keys
        Debug.Print key & ":" & Dict(key)
    Next

End Sub

結果は

1:a
2:b
3:c
4:d
5:e
6:f

Win/mac共にまったく同じ出力。完璧。

あとがき

githubの中の人であるtimhall氏のコードは大変勉強になる。ただ使わせていただくだけでなく、コードもしっかり読み込んで自身のツールに生かしていこう。