Scripting.Dictionaryのキーの比較

Scripting.Dictionaryのキーの比較

当方、VBA歴10年以上の当代きっての剛の者(ダニング・クルーガー効果)です。

ところが、長らく仕事で大量のデータを扱うことがなく、したがって〝データ構造〟というものを意識する機会が余りありませんでした。

そして、月日が流れ、いろいろありまして、急に大量のデータを扱うお仕事が増えました。

そこで、

Scripting.Dictionary

ですよ!

最近、特によく使うようになって、いろいろ試しているので、こちらでもぼちぼち紹介していこうかな、と……。

オブジェクトをキーにする?

Scripting.Dictionaryとは

「そんなこと知ってら!」という人はにスキップしてください。

VBAで大人気のScripting.Dictionary。

普通は、次のように〝キー・値〟の形でデータを保持するために使うと思います。

リスト1
Private Sub test01()
    ' Scripting.Dictionaryのインスタンスを取得
    Dim dic As Object
    Set dic = CreateObject("Scripting.Dictionary")
    ' Scripting.Dictionaryインスタンスにキーと値を闘魂注入
    Call dic.Add(Key:="pachinko", Item:=123)
End Sub

このようにすれば、"pachinko"をキーとして123という値を保持させることができ、

dic("pachinko")

としてやれば、123という値を取得することができます。

オブジェクトをキーにできる

私ほどの剛の者(ダニング・クルーガー効果)でさえ知らなかったぐらいですから、いわんやそこら辺の一般人においてをや。

実は、Scripting.Dictionaryでは、オブジェクトをキーにすることができてしまいます。

ちょっと何を言っているのかわかりませんね。

つまり、次のようなことができてしまうのです。

リスト2
Private Sub test02()
    Dim dic As Object, dicA As Object
    Set dic = CreateObject("Scripting.Dictionary")
    Set dicA = CreateObject("Scripting.Dictionary")
    Call dicA.Add(Key:="pachinko", Item:=123)
    Call dic.Add(Key:=dicA, Item:="ち~ん(笑)")
End Sub

こういうことです。

ちょっと何を言っているのかわからないかもしれませんが、上記リスト2のあとで、

Debug.Print dic(dicA)

とすると、イミディエイト ウィンドウに

ち~ん(笑)

と表示される、ということです。

〝同一キー〟の判定は?

さて、Scripting.Dictionaryでは、(当たり前ですが)同じキーの要素を追加することはできません。

リスト3
Private Sub test03()
    Dim dic As Object
    Set dic = CreateObject("Scripting.Dictionary")
    Call dic.Add(Key:="pachinko", Item:=123)
    Call dic.Add(Key:="pachinko", Item:=123)
End Sub

こんなことをすると、当然のことながら

このようにVBAに叱られます。(……っていうか、おまえ、「コレクション」やったんか……?)

では、次のようにしてみるとどうなるでしょうか。

リスト4
Private Sub test04()
    Dim dic As Object, dicA As Object
    Set dic = CreateObject("Scripting.Dictionary")
    Set dicA = CreateObject("Scripting.Dictionary")
    Call dicA.Add(Key:="pachinko", Item:=123)
    Call dic.Add(Key:=dicA, Item:="ち~ん(笑)")

    Dim dicB As Object
    Set dicB = CreateObject("Scripting.Dictionary")
    Call dicB.Add(Key:="pachinko", Item:=123)
    Call dic.Add(Key:=dicB, Item:="( ´,_ゝ`)プッ")
End Sub

dicAdicBも、〝キーが"pachinko"、値が123のディクショナリ〟なので、われわれ人間から見れば〝同じディクショナリ〟です。

とはいえ、リスト4はフツーに通ります。

なぜか。

dicAとdicBは別インスタンスだから

ですね。

言い方を変えると、

dicAとdicBはメモリ上の場所が違うから

です。

試みに、リストに続けて

Debug.Print (dicA Is dicB)

とすると、(別に()は要らないのですが、可読性のためにつけるようにしています。)イミディエイト ウィンドウに

False

が表示されます。

当然、リスト4を次のように書き換えると、今度は通りません。

リスト5
Private Sub test05()
    Dim dic As Object, dicA As Object
    Set dic = CreateObject("Scripting.Dictionary")
    Set dicA = CreateObject("Scripting.Dictionary")
    Call dicA.Add(Key:="pachinko", Item:=123)
    Call dic.Add(Key:=dicA, Item:="ち~ん(笑)")

    Dim dicB As Object
    Set dicB = dicA
    Call dicB.Add(Key:="pachinko", Item:=123)
    Call dic.Add(Key:=dicB, Item:="( ´,_ゝ`)プッ")
End Sub

このとおり。

叱られます。

おわりに

オブジェクトをScripting.Dictionaryにするようなケースって、一体どういうものがあるのでしょうか。

RangeオブジェクトにDictionaryとか配列、文字列なんかを紐づけて〝注釈〟みたいにするとかでしょうか……。

何か良い使いどころがあるなら、知りたいものです。