【VBA極限設計】CollectionとDictionaryの「正しい棲み分け」で、二度とキー重複エラーに泣かないために
業務自動化の現場でよく見かける光景がある。ループの中で`Collection.Add`を使い、キーが重複して「このキーは既にこのコレクションの要素に関連付けられています」というランタイムエラーでツールが停止する。あるいは、エラーを回避するために`On Error Resume Next`を多用し、デバッグ不可能なスパゲッティコードを量産する。
結論から言おう。現代のVBA開発において、Collectionは「一時的な順序付きリスト」としてのみ使い、キーを用いた「データ検索・一意性管理」には迷わずScripting.Dictionaryを採用すべきだ。
本稿では、この二つのオブジェクトの「本質的な違い」を解剖し、現場で即戦力となる堅牢な設計手法を伝授する。
—
1. なぜCollectionでキー管理をしてはいけないのか
Collectionは、インデックスアクセスとキーアクセスの両方に対応した「中途半端なユーティリティ」だ。
- キーの存在確認ができない: `Exists`メソッドが存在しないため、キーの重複チェックをするには、わざわざエラーハンドリングを仕込む必要がある。これは論理的な制御ではなく、例外処理によるフロー制御であり、非常に低品質な設計だ。
- 値の書き換えができない: `Add`で登録したアイテムは、一度追加すると後から変更できない(一度削除して追加し直す必要がある)。頻繁に更新が発生するマスタ管理には致命的だ。
—
2. Scripting.Dictionaryという「賢い選択」
Dictionaryは、ハッシュテーブルベースのデータ構造だ。キーの検索速度はO(1)、つまりデータが100個あろうが1万個あろうが、検索コストはほぼ変わらない。
現場で採用すべき「Dictionaryラッパー」の設計
単に`CreateObject`して使うのは初心者のやり方だ。実務では、「重複チェック」と「データ取得」を分離した設計を心がけるべきだ。
‘ 【プロダクションコード】堅牢な辞書管理クラスの例
‘ 外部ライブラリ参照設定なしで動作するLate Bindingを採用
Public Function GetUniqueDictionary(targetRange As Range) As Object
Dim dict As Object
Dim cell As Range
Set dict = CreateObject(“Scripting.Dictionary”)
For Each cell In targetRange
‘ キーが存在するかどうかを明示的に判定する
‘ これが堅牢なコードの第一歩
If Not dict.Exists(cell.Value) Then
dict.Add cell.Value, cell.Offset(0, 1).Value ‘ 検索キーをキーに、値をアイテムに格納
Else
‘ 重複時の挙動(ログ出力や上書き更新)をここに定義する
Debug.Print “重複検知: ” & cell.Value
End If
Next cell
Set GetUniqueDictionary = dict
End Function
—
3. 実務で使い分けるための「決定版ルール」
どちらを採用すべきか迷ったときは、以下の基準をチェックリストとして活用してほしい。
迷わず「Collection」を使うケース
- 順序が重要: データの挿入順序を保持したまま、あとからループで取り出すだけの場合。
- 超軽量な一時格納: キーによる検索が不要な、単純なリストとして扱う場合。
- 参照設定を極力減らしたい: 非常に特殊な環境で、WindowsのScripting Runtime(scrrun.dll)が使えない場合(極めて稀)。
迷わず「Dictionary」を使うケース
- 一意なマスタ管理: 社員IDや取引先コードなど、重複を許さないデータを扱う場合。
- 高速なルックアップ: 大量データの中から特定のキーに関連する値を取得する場合。
- 値の頻繁な更新: `dict(“Key”) = NewValue` という記法で、既存データを即座に更新したい場合。
—
4. 現場のアーキテクトからの忠告:パフォーマンスとメモリの罠
VBAでDictionaryを多用する際、一つだけ注意点がある。メモリ解放だ。
Dictionaryはオブジェクトであるため、プロシージャ終了時に明示的に`Set dict = Nothing`を呼び出す習慣を身につけること。特に、ループ内でDictionaryを何度も生成するような設計は、メモリリークの温床になる。
パフォーマンスを最大化するTips
- データ構造のフラット化: 入れ子状のDictionary(Dictionaryの中にDictionaryを入れる)は、可読性が著しく低下する。可能な限り、キーを連結して一意にするなど、フラットな構造を保て。
- 大量データ時は配列と併用: 10万行を超えるようなデータ処理を行う場合、セルへ直接アクセスせず、一度`Variant型配列`に全転送してから処理し、Dictionaryはあくまで「インデックス(辞書)」として活用せよ。
—
最後に:コードは「読み手」のためにある
「動けばいい」という考えは、開発者としての寿命を縮める。
キーの重複エラーで止まるツールは、ユーザーに不安を与える。エラーを隠蔽するコードは、保守担当者の時間を奪う。
今日からあなたのプロジェクトでは、「キー判定にはDictionary」というルールを徹底してほしい。技術的な正しさは、そのまま業務の安定性へと直結する。次の修正で、その場しのぎの`Collection`を、洗練された`Dictionary`に置き換えてみることから始めてみよう。
それが、伝説の自動化エンジニアへの第一歩だ。
