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
dicAもdicBも、〝キーが"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とか配列、文字列なんかを紐づけて〝注釈〟みたいにするとかでしょうか……。
何か良い使いどころがあるなら、知りたいものです。