【実務・中級編】コレクション(Collection)のキー重複エラーを回避する:辞書型(Dictionary)との賢い使い分け – Excel VBA解析バイブル

スポンサーリンク

【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`に置き換えてみることから始めてみよう。

それが、伝説の自動化エンジニアへの第一歩だ。

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