DictionaryはKeyからItemを取得するオブジェクトですが、
逆にItemからKeyを取得する方法を解説します。
といってもそんなプロパティはありませんので、
自作関数を作ってゴリ押しするよりほかありません。
ItemからKeyを取得する関数
はじめに、Dictionaryは「Key→Itemを紐づける」仕組みですので、
KeyはユニークですがItemはユニークではありません。
よってItemからKeyを取得するといっても、
結果のKeyがひとつとは限らないという点に注意してください。
こちらの対応策として、
- 最初に見つかったものを返す
- 複数あったらカンマ区切りで返す
- 常に配列を返す(一意に定まっても要素1の配列を返す)
の3パターンを作りましたのでセットでお持ち帰りください。
なお、「KeyもItemもすべて値」という想定で作成しております。
どちらかにオブジェクトをいれたDictionaryへの対応は適宜、自作してください。
最初に見つかったKeyを返す版
' 最初に見つかったものを返すVer Function GetDictionaryKey←Item_第1key(対象Dic As Dictionary, 対象Item As Variant) As Variant Dim key For Each key In 対象Dic.Keys If 対象Dic(key) = 対象Item Then GetDictionaryKey←Item_第1key = key Exit Function End If Next End Function
特に注意点などありません。
ストレートに「全Keyをループ→Itemが一致したらEixt」を実行したコードです。
複数見つかったらカンマ区切りで返す版
' カンマ区切りで返すVer Function GetDictionaryKey←Item_カンマ区切り(対象Dic As Dictionary, 対象Item As Variant _ , Optional 区切り文字 As String = ",") As String Dim 結果値 As String Dim key For Each key In 対象Dic.Keys If 対象Dic(key) = 対象Item Then 結果値 = 結果値 & 区切り文字 & key End If Next ' 最初の区切り文字を消して返す If 結果値 <> "" Then GetDictionaryKey←Item_カンマ区切り = Mid(結果値, Len(区切り文字) + 1) End Function
カンマと言いつつ元データがカンマを含む可能性があるので、
区切り文字を指定できる(省略時はカンマ)仕様としました。
注意点としてKeyの型が変わる可能性があり、
元のKeyがLong型だったとしても、String型で返ってしまいます。
区切り文字で返す以上、関数内ではどうしようもありませんので、
呼出元のコードで対応してください。
常に配列を返す版
' 常に配列を返すVer Function GetDictionaryKey←Item_配列(対象Dic As Dictionary, 対象Item As Variant) Dim 区切り文字 As String: 区切り文字 = "◆◇" GetDictionaryKey←Item_配列 = Split( _ GetDictionaryKey←Item_カンマ区切り(対象Dic, 対象Item, 区切り文字), 区切り文字) End Function
Dictionary内の配列をいじるのは面倒なので、
先ほどのカンマ版をSplitして対応しています。
正確にはStringの配列が返りますので、
先ほどと同様Keyの型が変わる可能性があることにご注意ください。
小ネタですが、最初に見つかったkeyを返す版も、
GetDictionaryKey←Item_配列(対象Dic,対象Item)(0)
で作れたりします。
これだと発見時のExit Functionによる高速化が出来なくなるので、
ちゃんと別に作りましたけどね。
KeyとItemを反転させたDictionaryを作る
上記の方法はすべてのItemごとにすべてのKeyをループするので、
もし全ItemでこれをやるとなるとO(n²)と激遅になってしまいます。
これを解決するには、
- 一旦KeyとItemを反転させたDictionaryを作る
- そのDictionaryの全key(元Dictionaryの全Item)をループする
という方法で対応します。
KeyとItemを反転させたDictionaryの生成関数がこちらです。
' Key⇔Item反転Dictionaryの生成 Function KeyとItemを反転させたDictionaryを生成(元Dic As Dictionary) As Dictionary ' 一旦区切り文字を使ったDictionaryを生成 Dim 区切り文字 As String: 区切り文字 = "◆◇" Dim 反転Dic_区切りstr As New Dictionary Dim 元key For Each 元key In 元Dic.Keys Dim 元Item: 元Item = 元Dic(元key) If 反転Dic_区切りstr.Exists(元Item) = False Then 反転Dic_区切りstr.Add 元Item, 元key Else 反転Dic_区切りstr(元Item) = 反転Dic_区切りstr(元Item) & 区切り文字 & 元key End If Next ' 全ItemをSplitで配列化 Dim 反転Dic_Arr As New Dictionary Dim key For Each key In 反転Dic_区切りstr.Keys 反転Dic_Arr.Add key, Split(反転Dic_区切りstr(key), 区切り文字) Next Set KeyとItemを反転させたDictionaryを生成 = 反転Dic_Arr End Function
Item(元DictionaryのKey)は汎用性を考え配列として持ちました。
例えば全Item-Keyのリストをイミディエイトウィンドウに出力するには、
以下のコードを実行すればよいことになります。
Dim 反転Dic As New Dictionary Set 反転Dic = KeyとItemを反転させたDictionaryを生成(元dic) Dim key For Each key In 反転Dic.Keys Debug.Print key, Join(反転Dic(key)) Next
すべてのItemからKeyを逆取得するようなときは、この関数をご活用ください。