【ArrayList活用】VBScriptの常識を覆す!.NET COM連携による超高速データソート術
プログラミングの世界において、VBScriptはすでにレガシーな言語として扱われることが多い。しかし、現場のインフラや業務自動化(RPA、レガシーシステムのバッチ処理、キッティングスクリプトなど)の領域では、今なお「インストールの手間がなく、Windows環境さえあればどこでも動く」という最強の武器として君臨し続けている。
さて、VBScriptで開発を行う際、多くのエンジニアが一度は絶望するポイントがある。
そう、「配列のソート(並べ替え)が圧倒的に面倒くさい」という点だ。
ネイティブの `VBScript` には、配列をサクッとソートするような洗練されたメソッドが存在しない。そのため、昔のプログラマは自前でバブルソートやクイックソートのアルゴリズムを何十行も書き下ろすか、無理やりDictionaryオブジェクトのキーに突っ込んでソート気味に扱うという不毛なハックを行ってきた。
だが、非効率な自前実装はもう終わりだ。
今回は、Windowsに標準搭載されている.NET FrameworkのCOMコンポーネント `System.Collections.ArrayList` をVBScriptから召喚し、圧倒的なパフォーマンスと極小のコード量でデータをソートする極限の知見を伝授する。
—
なぜ「自前ソート」は悪手なのか?
業務自動化ツールを構築する際、可読性と保守性は正義である。
数万行のCSVデータや、DBから取得した動的リストを処理する際、VBScriptのプリミティブな配列に対して自前でソートアルゴリズムを実装すると、以下のような致命的な問題が発生する。
1. コードの肥大化と可読性の崩壊:ソートごときに20〜30行のロジックを挟むのは、後からコードを見る人間(あるいは半年後の自分)にとって苦痛でしかない。
2. 処理速度の限界:O($N^2$) のバブルソートなどをVBScriptのインタプリタ上で回すと、データ量が数千件を超えたあたりから露骨に処理が重くなり、実務に耐えなくなる。
3. バグの温床:境界値エラーや、型違いによる比較エラーなど、ソートアルゴリズム特有のバグに悩まされる時間が無駄。
ここで登場するのが、.NET Frameworkが誇る堅牢なデータ構造「ArrayList」だ。
VBScriptから `CreateObject(“System.Collections.ArrayList”)` を実行するだけで、裏側では最適化された.NETのマネージドコードが動き、一瞬でソートを完了させてくれる。これを使わない手はない。
—
実装:プロダクションコード例
現場でそのままコピペして使える、極めて堅牢かつ実用的なサンプルコードを提示する。
このコードでは、単なる数値・文字列のソートだけでなく、実務で必須となる「重複排除(ユニーク化)」や「降順ソート」のテクニックまで網羅している。
‘ ==============================================================================
‘ スクリプト名: ArrayListSortSample.vbs
‘ 概要 : .NET ArrayListを用いた超高速データソート&重複排除の実装例
‘ 著者 : チーフアーキテクト
‘ ==============================================================================
Option Explicit
Main
Sub Main()
‘ 1. ArrayListオブジェクトの生成
‘ ※ 注意: .NET Framework 3.5 / 4.0 が有効なWindows環境であれば動作します
Dim al
Set al = CreateObject(“System.Collections.ArrayList”)
‘ 2. テストデータの追加(順不同、重複あり)
‘ VBScriptの配列と違い、動的にサイズが拡張されるためReDimの必要がありません
al.Add “Banana”
al.Add “Apple”
al.Add “Orange”
al.Add “Apple” 重複データ
al.Add “Grape”
al.Add “Cherry”
WScript.Echo “— 【元データ】 —”
PrintArrayList al
‘ 3. 昇順ソート (Ascending)
al.Sort()
WScript.Echo vbCrLf & “— 【昇順ソート後】 —”
PrintArrayList al
‘ 4. 降順ソート (Descending)
‘ Sortした後に Reverse を呼び出すだけで、O(N)のコストで降順に反転できます
al.Reverse()
WScript.Echo vbCrLf & “— 【降順ソート後】 —”
PrintArrayList al
‘ 5. 実務で必須:重複データの排除(ユニーク化)
‘ 一度クリアして、別のデータで実験
al.Clear()
al.Add 100
al.Add 20
al.Add 50
al.Add 100 ‘ 重複
al.Add 10
al.Add 50 ‘ 重複
WScript.Echo vbCrLf & “— 【数値データ(重複あり)】 —”
PrintArrayList al
al.Sort() ‘ まずソートする
‘ 連続する重複要素を後ろから削除する(前方から消すとインデックスがズレるため注意)
Dim i
For i = al.Count – 1 To 1 Step -1
If al.Item(i) = al.Item(i – 1) Then
al.RemoveAt(i)
End If
Next
WScript.Echo vbCrLf & “— 【ソート & 重複排除後】 —”
PrintArrayList al
‘ クリーンアップ
Set al = Nothing
End Sub
‘ ——————————————————————————
‘ 補助関数: ArrayListの中身をコンソールに出力する
‘ ——————————————————————————
Sub PrintArrayList(ByVal targetList)
Dim item
For Each item In targetList
WScript.Echo ” -> ” & item
Next
End Sub
—
現場で絶対に知っておくべき「3つの罠」とアーキテクトの知見
この手法は非常に強力だが、COMインターフェースを介した異言語間の連携(COM Interop)である以上、VBScript特有の罠が存在する。実務で事故を起こさないために、以下の3点を心に刻んでおいてほしい。
1. 型の不一致による比較エラー(Type Mismatch)
`ArrayList.Sort()` は、格納されている要素同士を比較して並べ替える。
もし、ひとつのArrayListの中に 「数値 (Integer/Long)」 と 「文字列 (String)」 が混在している場合、`.Sort()` を呼び出した瞬間に `型が一致しません` というランタイムエラーが発生する。
- 対策: ArrayListにデータを投入する際は、必ずデータ型を統一(CStr関数やCLng関数でキャスト)してからAddすること。
2. 環境依存性(.NET Frameworkの有効性)
`System.Collections.ArrayList` は .NET Framework のクラスである。現代のWindows 10 / 11 や Windows Server 環境であれば標準で稼働するが、極端に古いレガシー環境や、セキュリティポリシーで.NETコンポーネントの呼び出しが制限されている特殊な閉域網では動作しない場合がある。
- 対策: 対象端末のインフラ要件を事前に確認すること。また、よりモダンな環境であれば `System.Collections.Generic.List` を使いたいところだが、VBScriptのCOMからはジェネリック型を直接扱えないため、ArrayListがVBScriptにおける事実上の最適解となる。
3. オブジェクトのライフサイクル管理
VBScriptにおけるCOMオブジェクトの解放 (`Set xxx = Nothing`) は、メモリリークを防ぐために重要である。特にループ内で何度も `CreateObject(“System.Collections.ArrayList”)` を呼び出すような設計は、パフォーマンスを著しく低下させる。
- 対策: ループの外側でオブジェクトを一度だけ生成し、使い回す場合は `.Clear()` メソッドで中身を空にして再利用する設計を徹底すること。
—
まとめ
VBScriptというレガシーな言語であっても、モダンな.NETの資産(COMコンポーネント)を適切にアプローチに組み込むことで、見違えるほど堅牢で高速なプログラムに生まれ変わらせることができる。
「VBScriptだから遅い、書くのが面倒くさい」というのは、言語のせいではなく設計の怠慢だ。
今回紹介した `ArrayList` を駆使し、あなたの管理する業務自動化スクリプトを、よりスマートで強固なものにアップデートしてほしい。
