【入門編】Dictionaryオブジェクトのキーにユーザー定義型を使用する際のハッシュ化戦略 – Excel VBA解析バイブル

スポンサーリンク

こんにちは!Excel VBAのスキルを次のステージへと引き上げる、熱い情熱を持った開発者の皆さん。

マクロの記録から一歩抜け出し、「もっとスマートに、もっと高速にデータを処理したい!」と思ったときに出会うのが、VBAにおける最強の武器の一つ、`Scripting.Dictionary`(連想配列)ですね。

キーを指定して一瞬で値を取り出せるDictionaryは、重複排除やマスターデータの突合において圧倒的なパフォーマンスを発揮します。しかし、ここで一つ、多くのVBAエンジニアがぶ Walls(壁)があります。

「文字列や数値だけでなく、複数の項目をまとめた『ユーザー定義型(Type)』を、そのままDictionaryのキーにしたい!」

さて、ここで問題です。実は、Dictionaryのキーにユーザー定義型(UDT)をそのまま渡すと、VBAは冷たくこうエラーを吐きます。

> 実行エラー ’13’: 型が一致しません。

「えっ、構造体をキーにできないの……?」
安心してください。道はあります。今回は、オブジェクトのライフサイクルとメモリの裏側を知り尽くしたシニアエンジニアの視点から、「ユーザー定義型をハッシュ化してDictionaryのキーにする極限のテクニック」を、優しく、かつ深く解説していきましょう。

ここをクリアすれば、あなたのVBAのデータ構造デザインは、プロの領域へと一気に飛躍しますよ!

1. なぜユーザー定義型をそのままキーにできないのか?

まず、敵を知ることから始めましょう。なぜDictionaryはユーザー定義型(Typeで定義した構造体)をキーとして受け付けないのでしょうか?

それは、「ハッシュ値(一意の識別子)を計算できないから」です。

Dictionaryは、内部でキーの「ハッシュ値」を計算し、メモリ上のどこにデータがあるかをO(1)(一瞬)で特定しています。

  • 文字列 `”Apple”` なら、その文字の並びからハッシュを作れます。
  • 数値 `123` なら、その数値からハッシュを作れます。

しかし、あなたが作ったユーザー定義型(例えば「社員ID」と「部署コード」を持つ構造体)は、VBAにとって「中身がどうなっているか複雑すぎて、一意に要約(ハッシュ化)できない未知の塊」なのです。

「じゃあ、どうすればいいのか?」
答えはシンプルです。「ユーザー定義型の中身を結合して、一意の『文字列(ハッシュ文字列)』に変換してからキーにすればいい」のです。これが本記事の核心である【ハッシュ化戦略】です。

2. 実践!ハッシュ化戦略によるDictionary実装

百聞は一見にしかず。実際のコードを見てみましょう。
今回は、「部署コード」と「社員ID」の2つの要素を持つユーザー定義型をキーにして、それぞれの「氏名」をDictionaryで管理するシナリオを考えてみます。

以下のコードを、標準モジュールにそのまま貼り付けて実行してみてください。

Option Explicit

‘ ==========================================
‘ 1. ユーザー定義型(キーの元となる構造体)の定義
‘ ==========================================
Public Type TEmployeeKey
DepartmentCode As String ‘ 部署コード
EmployeeID As Long ‘ 社員ID
End Type

Sub Demo_CustomTypeKeyDictionary()
‘ 事前に参照設定で「Microsoft Scripting Runtime」を追加するか、
‘ アーリーバインディング/レイトバインディングを使用します。
Dim dict As Object
Set dict = CreateObject(“Scripting.Dictionary”)

‘ テストデータの作成
Dim key1 As TEmployeeKey
key1.DepartmentCode = “SALES”
key1.EmployeeID = 101

Dim key2 As TEmployeeKey
key2.DepartmentCode = “DEV”
key2.EmployeeID = 101 ‘ IDは同じでも部署が違う

‘ ==========================================
‘ 2. 登録(ハッシュ化関数の適用)
‘ ==========================================
Dim hashKey1 As String
hashKey1 = GetUserDefinedKeyHash(key1)

Dim hashKey2 As String
hashKey2 = GetUserDefinedKeyHash(key2)

‘ Dictionaryに値を格納
dict.Add hashKey1, “山田 太郎(営業部)”
dict.Add hashKey2, “佐藤 花子(開発部)”

‘ ==========================================
‘ 3. 検索(同じ構造体からハッシュを作って取得)
‘ ==========================================
Dim searchKey As TEmployeeKey
searchKey.DepartmentCode = “DEV”
searchKey.EmployeeID = 101

Dim searchHash As String
searchHash = GetUserDefinedKeyHash(searchKey)

If dict.Exists(searchHash) Then
MsgBox “見つかりました! 担当者: ” & dict(searchHash), vbInformation, “検索成功”
Else
MsgBox “データが存在しません。”, vbExclamation, “検索失敗”
End If

End Sub

‘ ==========================================
‘ 4. ハッシュ生成関数(ここがキモ!)
‘ ==========================================
Private Function GetUserDefinedKeyHash(ByRef udtKey As TEmployeeKey) As String
‘ メンバー同士が混ざらないように「区切り文字(デリミタ)」を挟むのが鉄則
Const DELIMITER As String = “_”

‘ 各要素を結合して一意の文字列を生成する
GetUserDefinedKeyHash = udtKey.DepartmentCode & DELIMITER & CStr(udtKey.EmployeeID)
End Function

コードの解説:ここがプロの技

1. デリミタ(区切り文字)の重要性
ハッシュ生成関数 `GetUserDefinedKeyHash` を見てください。`DepartmentCode` と `EmployeeID` をそのまま繋ぐのではなく、`_`(アンダースコア)などの区切り文字を挟んでいます。
もしこれを怠ると、部署コード `”A”`、社員ID `”12″(”A12″)` と、部署コード `”AB”`、社員ID `”2″(”AB2″)` が、結合したときに同じ文字列 `”AB2″` になってしまい、致命的なデータ衝突(コリジョン)を起こします。区切り文字は必ず入れましょう。
2. ByRefによるパフォーマンス最適化
構造体を引数に取る際、`ByRef`(参照渡し)にすることで、メモリ上の無駄なコピーを防ぎ、処理速度を極限まで高めています。大規模データを扱うVBAにおいて、この小さな配慮が動作の軽快さを生みます。

3. 陥りやすいエラーと実務での注意点

このハッシュ化戦略を使うにあたって、現場でやりがちなミスをいくつか予習しておきましょう。

注意点①:大文字・小文字の区別(大文字小文字問題)

Dictionaryはデフォルトで大文字・小文字を区別します(`”Sales”` と `”sales”` は別物扱い)。
もし部署コードなどで大文字小文字を同一視したい場合は、ハッシュ化する段階で事前に `UCase` や `LCase` で正規化しておくのがプロの作法です。

GetUserDefinedKeyHash = UCase(udtKey.DepartmentCode) & “_” & udtKey.EmployeeID

注意点②:構造体がネスト(入れ子)している場合

構造体の中にさらに別の構造体が含まれている場合も、ハッシュ化関数の中でそれぞれの要素を展開して連結すれば問題なく対応できます。データ構造がどれだけ複雑になっても、「最終的に一意の文字列に縮約する」という原則さえ守れば、Dictionaryは完全にあなたの味方をしてくれます。

まとめ:データ構造のデザインを楽しもう!

今回は、「Dictionaryオブジェクトのキーにユーザー定義型を使用する際のハッシュ化戦略」について解説しました。

  • ユーザー定義型はそのままではDictionaryのキーにできない。
  • 解決策として、構造体の各要素をデリミタ付きで結合し、一意の「ハッシュ文字列」に変換する関数を用意する。
  • データの衝突(コリジョン)を防ぐために、区切り文字や大文字小文字の正規化に気を配る。

ここまで理解できたあなたなら、もう「マクロの記録をちょこっと直すだけの初学者」ではありません。メモリ効率やアルゴリズムの整合性まで意識できる、立派な「VBAアーキテクト」です。

現場の複雑なデータ処理に直面したとき、ぜひこのハッシュ化テクニックを思い出してください。あなたのVBAコードが、より美しく、圧倒的に高速に生まれ変わるはずです。

それでは、次回の極限の知見でお会いしましょう。ハッピー・コーディング!

タイトルとURLをコピーしました