VBScriptを極める:Scripting.Dictionaryによる「高速データ処理」の鉄則
現場でよく見かける「遅いスクリプト」の典型例を知っているか?
それは、配列の二重ループで重複チェックを行い、`If`文で比較し続けるようなコードだ。
データ量が1,000件程度なら誤差かもしれない。だが、10万件を超えるログ解析やマスター照合を扱うとき、その実装はシステムを停止させる爆弾と化す。
今日は、VBScriptのポテンシャルを最大限に引き出し、計算量を劇的に改善する`Scripting.Dictionary`を活用した「高速データ処理」の極意を授ける。
—
1. なぜ「配列のループ」ではいけないのか
計算量理論の基礎だが、配列の中にデータが存在するかをループで毎回確認する(線形探索)と、計算量はデータ数 $N$ に対して $O(N^2)$ になる。
- 10,000件のデータ:約1億回の比較
- 100,000件のデータ:約100億回の比較
これでは業務ツールとしては失格だ。対して、`Scripting.Dictionary`はハッシュテーブル構造を持つ。キーによるアクセスは $O(1)$ 、つまりデータ数に関わらず一瞬で完了する。これを活用しない手はない。
—
2. 堅牢な実装:Scripting.Dictionaryによる高速重複排除
以下は、大量のログデータから「ユニークな項目」を抽出し、集計するプロダクションレベルのコードだ。
Option Explicit
‘ メイン処理:高速な重複排除と出現回数のカウント
Sub ProcessLargeData()
Dim dict: Set dict = CreateObject(“Scripting.Dictionary”)
Dim rawData: rawData = Array(“Apple”, “Orange”, “Apple”, “Banana”, “Orange”, “Apple”)
Dim item, count
‘ 1. 高速な集計ループ
For Each item In rawData
‘ キーが存在しなければ追加、存在すればカウントアップ
If Not dict.Exists(item) Then
dict.Add item, 1
Else
dict(item) = dict(item) + 1
End If
Next
‘ 2. 結果の出力(保守性を考慮した列挙)
Dim key
For Each key In dict.Keys
WScript.Echo “項目: ” & key & ” | 回数: ” & dict(key)
Next
‘ 3. オブジェクトの解放(メモリ管理の徹底)
Set dict = Nothing
End Sub
ProcessLargeData
このコードが「現場」で評価される理由
- `Option Explicit`の強制: 変数の宣言漏れによるデバッグ地獄を未然に防ぐ。
- `Exists`メソッドの活用: キーの重複を検証するロジックを分離し、可読性を最大化している。
- メモリ解放: 巨大なデータを扱う際、`Set Nothing`を怠るとCOMオブジェクトの残骸がリークの原因となる。
—
3. 実務でハマる「落とし穴」と回避策
大文字・小文字の区別問題
`Scripting.Dictionary`は、デフォルトで大文字・小文字を区別する。`”Data”`と`”data”`を同一視したい場合は、`CompareMode`を設定せよ。
‘ 比較モードを「テキスト比較(大文字小文字を区別しない)」に設定
dict.CompareMode = 1 ‘ 0=Binary, 1=Text
ファイルやDBとの連携時
大量のデータをファイルから読み込む際は、`ADODB.Stream`や`FileSystemObject`の`ReadLine`を併用するはずだ。その際、「処理のたびにファイルを開く・閉じる」は絶対に行うな。 一度メモリ上にDictionaryとして展開し、処理後に一括書き込みする設計こそが、I/Oボトルネックを解消する鍵だ。
—
4. アーキテクトからの提言
VBScriptは古い言語だと揶揄されることもある。だが、OS標準でインストールされており、依存関係なしに即座に実行できるという強みは、エンタープライズ環境において何物にも代えがたい「武器」だ。
「動けばいい」コードから「計算量を意識した」コードへ。
この視点を持つだけで、君の書くスクリプトの価値は桁違いに跳ね上がる。まずは、既存のツールの中で「ループが重い」と感じる箇所を、このDictionaryパターンに書き換えてみてほしい。
それが、自動化エンジニアとして次のステージへ進むための第一歩だ。
