VBAにおける1次元配列の並べ替え:アルゴリズムの選択と実装
Excel VBAでデータ処理を行う際、セル範囲を直接操作するのではなく、一度メモリ上の「配列」に取り込んでから処理を行うことは、処理速度を劇的に向上させるための基本中の基本です。しかし、配列に取り込んだデータを目的の順序に並べ替える(ソートする)ための標準関数は、残念ながらVBAには存在しません。
本記事では、プロのエンジニアとして知っておくべき「バブルソート」「挿入ソート」「クイックソート」という3つの代表的なアルゴリズムを取り上げ、それぞれの特性とVBAでの実装方法を徹底解説します。
アルゴリズムの特性と選択基準
VBAでソートを行う際、データ量と実行速度のバランスを考慮する必要があります。
1. バブルソート(隣接交換法):隣り合う要素を比較し、順序が逆であれば入れ替える手法。実装は極めて容易ですが、計算量はO(n²)であり、データ量が数千件を超えると実用に耐えません。小規模な配列のテスト用として利用します。
2. 挿入ソート:整列済みの部分に新しい要素を適切な位置に挿入していく手法。データが既にある程度整列されている場合に非常に高速です。小規模から中規模のデータに適しています。
3. クイックソート:分割統治法を用いたアルゴリズム。計算量は平均でO(n log n)となり、今回紹介する中では最も高速です。実務において数万件以上のデータを扱う場合は、このクイックソート一択となります。
バブルソートの実装
バブルソートは、配列の端から隣同士を比較し、昇順であれば後ろが大きくなるように入れ替えていく手法です。コードの簡潔さは随一ですが、効率は悪いため、学習用や非常に小さな配列(100件以下程度)に限定して使用してください。
Sub BubbleSort(arr As Variant)
Dim i As Long, j As Long
Dim temp As Variant
Dim n As Long
n = UBound(arr) - LBound(arr) + 1
For i = LBound(arr) To UBound(arr) - 1
For j = UBound(arr) To i + 1 Step -1
If arr(j - 1) > arr(j) Then
temp = arr(j - 1)
arr(j - 1) = arr(j)
arr(j) = temp
End If
Next j
Next i
End Sub
挿入ソートの実装
挿入ソートは、リストを「整列済み」と「未整列」の2つに分け、未整列の先頭要素を整列済みリストの適切な位置に挿入していく手法です。バブルソートよりも比較回数が少なく、安定したパフォーマンスを発揮します。
Sub InsertionSort(arr As Variant)
Dim i As Long, j As Long
Dim target As Variant
For i = LBound(arr) + 1 To UBound(arr)
target = arr(i)
j = i - 1
' 適切な挿入位置を探しながら後ろへずらす
Do While j >= LBound(arr) And arr(j) > target
arr(j + 1) = arr(j)
j = j - 1
Loop
arr(j + 1) = target
Next i
End Sub
クイックソートの実装
クイックソートは、基準値(ピボット)を決め、それより小さいグループと大きいグループに分割し、それぞれを再帰的にソートします。VBAで大量のデータを扱う場合、再帰呼び出しのオーバーヘッドを考慮しても、このアルゴリズムが最も高速です。
Sub QuickSort(arr As Variant, ByVal left As Long, ByVal right As Long)
Dim i As Long, j As Long
Dim pivot As Variant
Dim temp As Variant
i = left
j = right
pivot = arr((left + right) \ 2)
Do
Do While arr(i) < pivot: i = i + 1: Loop
Do While arr(j) > pivot: j = j - 1: Loop
If i <= j Then
temp = arr(i)
arr(i) = arr(j)
arr(j) = temp
i = i + 1
j = j - 1
End If
Loop Until i > j
If left < j Then QuickSort arr, left, j
If i < right Then QuickSort arr, i, right
End Sub
実務におけるエンジニアリングの視点
実務でVBAを使用する際、単にアルゴリズムを書くだけでは不十分です。以下のポイントを意識することで、より堅牢でプロフェッショナルなコードになります。
1. 配列の境界チェック:LBound(arr) と UBound(arr) を必ず使用し、固定値(0や1)を直接書かないようにします。これにより、Option Base 1の設定や、フィルタリング後の配列など、様々なケースに対応可能となります。
2. データ型の意識:Variant型は柔軟ですが、メモリを多く消費し速度も低下します。数値のみの配列であれば、Long型やDouble型の配列として定義し、型を明示することでパフォーマンスが向上します。
3. 再帰呼び出しの制限:クイックソートは再帰呼び出しを行うため、非常に深い階層になるとスタックオーバーフローが発生するリスクがあります。数百万件を超えるような極端なデータ量の場合は、非再帰版のクイックソートを検討するか、あるいは別のソートアルゴリズム(ヒープソートなど)を採用する必要があります。
4. 既存機能との比較:もしVBAでソートした結果を再度シートに出力するだけなら、メモリ上の配列をソートするよりも、一旦シートに書き出し、Excelの標準機能である「Range.Sort」メソッドや「ワークシート関数」を利用する方が圧倒的に速い場合があります。VBAでソートを実装すべきは、「メモリ上で完結する複雑なロジックの一部」であるときのみ、という判断基準を持つことが重要です。
まとめ
VBAにおけるソートの実装は、アルゴリズムの基礎教養を試す良い機会です。
- 小規模な処理やデバッグ用には「バブルソート」
- 中規模かつ既にある程度整列されているデータには「挿入ソート」
- 大規模なデータには「クイックソート」
これらを使い分けることで、あなたの書くVBAプログラムの品質は一段上のレベルへと到達します。コードを書く際は、常に「なぜこのアルゴリズムを選んだのか」という設計思想を持つようにしてください。それが、単なるコード書きからプロフェッショナルなエンジニアへと脱皮するための第一歩です。
今回紹介したコードは、そのままモジュールに貼り付けて利用可能です。まずは小さなデータセットで挙動を確認し、その後、実務のデータ量に合わせて最適化を試みてください。配列操作をマスターすることは、VBAによる自動化の可能性を無限に広げる鍵となります。
