こんにちは、ふみです。みなさんは VBScript で2次元配列を並び替えに時間がかかりすぎると思ったことはありますか?
私はプログラムで2次元配列を並び替えるときはマージソートと挿入ソートを組み合わせたものを使います。
マージソートと挿入ソートを組み合わせたものは1万件を超えるような配列のデータでも、ソート(データの並び替え)が速く、安定ソートなので2次元配列のソートには便利です。
今回はマージソートと挿入ソートを組み合わせたものを使って2次元配列をソートする方法ついて紹介します。
【2025/9/11サンプルコードの表示の不具合を修正しました】
CONTENTS
2次元配列の並べ替えについて
重複データは安定ソートを使う
2次元配列の並べ替えで注意しなければならない点は、並べ替えの対象における重複データの有無です。
例えば、2次元配列の要素に120円のりんごと100円のりんごがあるときに、値段で並び替えた後に商品名で並び替えるとします。
並び替えの方法が安定ソートの場合、りんご100円、りんご120円の順番になります。しかし、不安定ソートの場合は重複データのある商品名で並び替えた時に、りんご120円、りんご100円と、値段の順番が崩れてしまう可能性があります。
よって、並べ替えの対象に重複データがある場合、並び替えのアルゴリズムは安定ソートを使う必要があります。2次元配列の並び替えは安定ソート推奨と覚えておきましょう。
重複データが無い(排他的の)場合の並び替えはクイックソート等の不安定なソートでも問題ありません。
並び替える前の添字(INDEX)の配列をつくる
2次元配列では要素の並び替えの時に他の項目も同時に連動して要素の入れ替えをした場合、配列の項目の数に比例して要素を入れ替える回数が増えます。
これは2次元配列を Microsoft Excel のワークシートに例えると、2列の配列を縦方向に選択範囲を拡張して並び替える場合に比べて、20列の配列を縦方向に選択範囲を拡張して並び替えると要素の入れ替え回数が 20÷2=10倍に増える状態です。
そこで、要素の入れ替え回数を減らす(ソート時間を短縮する)為に、並び替える要素以外の全ての要素を並び替える前の添字(ソート以前のINDEX)に置き換える方法を使います。
まず、並び替える要素以外の全ての要素を一つの添字(ソート以前のINDEX)に置き換えます。
次に、要素の並び替えの時、ソート以前のINDEXも同時に並び替えます。
最後に、ソート以前のINDEXを参照して2次元配列の要素をまとめて入れ替えます。
この方法は、2次元配列でソートしない方向の要素数が3以上のときに、入れ替え回数を減らす(ソート時間を短縮する)効果があります。
ソートのしくみ
マージソート
マージソートの動作のしくみは次のとおりです。
1.
配列の添字0番と1番を比較して2つの要素を順番に並べる。添字2番と3番を比較して2つの要素を順番に並べる。添字4番と5番を比較…
これを最後の添字まで繰り返す。
2.
添字0番と1番の配列と2番と3番の配列の若番を比較して4つの要素を順番に並べる。添字4番と5番の配列と6番と7番の配列の若番を比較…
これを最後の添字まで繰り返す。
3.
添字0~3番の配列と4~7番の配列の若番を比較し8つの要素を順番に並べる。添字8~11番の配列と12~15番の配列の若番を比較…
これを最後の添字まで繰り返す。
4.
以降、同様の手順で配列要素の全てが順番につながるまで続ける
この手順をプログラム用に効率化したものがマージソートのプログラムです。
マージソートは大きなデータにおいて短時間で並び替えができるのが特徴です。
マージソートは重複する値を含む(排他的でない)配列をソートした時に順番が入れ替わらないソートです。(安定ソート)
挿入ソート
挿入ソートの動作のしくみは次のとおりです。
1.
配列の添字の若番(0番)の要素と次(1番)の要素を比較し、入れ替える。
2.
その次(2番)の要素と、左側の配列(0~1番)の要素を比較し、順番になる位置に要素を挿入する。さらに次(3番)の要素と、左側の配列(0~2番)の要素を比較…
これを配列の最後になるまで、要素の比較と挿入を繰り返す。
この手順をプログラム用に効率化したものが挿入ソートのプログラムです。
挿入ソートは少ないデータにおいて短時間で並び替えができるのが特徴です。
挿入ソートもマージソートと同様に、重複する値を含む(排他的でない)配列をソートした時に順番が入れ替わらないソートです。(安定ソート)
マージソートと挿入ソートの組み合わせ
マージソートと挿入ソートの長所を生かして、配列のデータが多いときはマージソートを使い、マージソートの配列の分割でデータが少なくなったときに挿入ソートへ切り替えると、短時間で並び替える安定ソートを実現することができます。動作のしくみは次のとおりです。
1.
配列の要素の数を確認し、閾値(しきいち)以下の時は挿入ソートで配列を並べ替えて終了。閾値より多い時は配列を左右に分割した各配列を1.からの順序でやり直す(再帰処理)。
2.
1.で左右に分割した各配列の並び替えが完了しているので、左右の配列を若番から順に値を比較して、新しい配列に並べ替える。
この手順をプログラム用に効率化したものが今回紹介する、マージソートと挿入ソートを組みわせたプログラムです。配列の分割で少なくなった並び替えを挿入ソートに切り替えることにより、マージソートよりも短時間で並び替えることができます。
2次元配列を2番目の次元の範囲で昇順に並び替える(安定ソート)
2次元配列を2番目の次元の範囲(Microsoft Excel のワークシートの配列では横方向)で昇順に並び替えるプログラムは次のとおりです。
サンプルコード
Option Explicit
Dim varArray, sngTime, lngN1, lngN2
ReDim varArray(2, 16383)
For lngN1 = LBound(varArray, 1) To UBound(varArray, 1)
For lngN2 = LBound(varArray, 2) To UBound(varArray, 2)
varArray(lngN1, lngN2) = Int(Rnd * ((UBound(varArray, 1) + 1) _
* (UBound(varArray, 2) + 1) + 1))
Next
Next
sngTime = Timer
Call MergeSort2D(varArray, 0, 16383, 2, 2)
Call MergeSort2D(varArray, 0, 16383, 2, 1)
Call MergeSort2D(varArray, 0, 16383, 2, 0)
MsgBox ConfirmationTextForArray2D(varArray, False, True), , _
"並び替え処理の時間(秒):" & Round(Timer - sngTime, 3)
WScript.Quit
'******************************************************************************
'処 理:2次元配列のデータを昇順に並び替える(マージソート、挿入ソート)
'
'引 数:varArray2D - 2次元配列
' lngLower - 並び替え範囲下限の添字(INDEX)
' lngUpper - 並び替え範囲上限の添字
' intDimension - 並び替え範囲の添字の次元
' lngTgtIndex - 並び替えの基準となる添字(intDimensionでない次元)
'
'備 考:関数 MergeSortedArray2D、InsertionSortedArray2D を使用
'
Sub MergeSort2D(ByRef varArray2D, ByVal lngLower, ByVal lngUpper _
, ByVal intDimension, ByVal lngTgtIndex)
Dim lngRange, lngI, lngJ, lngN1, lngN2
Dim varTgtArray, varSortedArray, varNewArray2D
lngRange = lngUpper - lngLower
If lngRange = 0 Then Exit Sub 'ソート不要
ReDim varTgtArray(1, lngRange) '並べ替える要素とソートする前の添字の配列
Select Case intDimension
Case 1
For lngN1 = lngLower To lngUpper
lngI = lngN1 - lngLower
varTgtArray(0, lngI) = varArray2D(lngN1, lngTgtIndex)
varTgtArray(1, lngI) = lngN1 'ソートする前の添字
Next
If lngTgtIndex < LBound(varArray2D, 2) Then
Error 13 '引数が不正
ElseIf lngTgtIndex > UBound(varArray2D, 2) Then
Error 13 '引数が不正
End If
Case 2
For lngN2 = lngLower To lngUpper
lngI = lngN2 - lngLower
varTgtArray(0, lngI) = varArray2D(lngTgtIndex, lngN2)
varTgtArray(1, lngI) = lngN2 'ソートする前の添字
Next
If lngTgtIndex < LBound(varArray2D, 1) Then
Error 13 '引数が不正
ElseIf lngTgtIndex > UBound(varArray2D, 1) Then
Error 13 '引数が不正
End If
Case Else
Error 13 '引数が不正
End Select
If lngLower < LBound(varArray2D, intDimension) Then
Error 13 '引数が不正
ElseIf lngUpper > UBound(varArray2D, intDimension) Then
Error 13 '引数が不正
End If
varSortedArray = MergeSortedArray2D(varTgtArray, 0, lngRange)
Select Case intDimension
Case 1
ReDim varNewArray2D(lngRange _
, UBound(varArray2D, 2) - LBound(varArray2D, 2))
For lngI = 0 To UBound(varSortedArray, 2)
For lngN2 = LBound(varArray2D, 2) To UBound(varArray2D, 2)
lngJ = lngN2 - LBound(varArray2D, 2)
varNewArray2D(lngI, lngJ) _
= varArray2D(varSortedArray(1, lngI), lngN2)
Next
Next
Case 2
ReDim varNewArray2D(UBound(varArray2D, 1) - LBound(varArray2D, 1) _
, lngRange)
For lngI = 0 To UBound(varSortedArray, 2)
For lngN1 = LBound(varArray2D, 1) To UBound(varArray2D, 1)
lngJ = lngN1 - LBound(varArray2D, 1)
varNewArray2D(lngJ, lngI) _
= varArray2D(lngN1, varSortedArray(1, lngI))
Next
Next
Case Else
End Select
If LBound(varArray2D, 1) = 0 And LBound(varArray2D, 2) = 0 _
And UBound(varArray2D, 1) = UBound(varNewArray2D, 1) _
And UBound(varArray2D, 2) = UBound(varNewArray2D, 2) Then
On Error Resume Next
varArray2D = varNewArray2D '引数が配列として宣言されていた場合はエラー
If Err.Number = 0 Then
On Error GoTo 0
Exit Sub
End If
On Error GoTo 0
End If
'引数が配列として宣言されていた場合の処理
Select Case intDimension
Case 1
For lngN1 = lngLower To lngUpper
lngI = lngN1 - lngLower
For lngN2 = LBound(varArray2D, 2) To UBound(varArray2D, 2)
lngJ = lngN2 - LBound(varArray2D, 2)
varArray2D(lngN1, lngN2) = varNewArray2D(lngI, lngJ)
Next
Next
Case 2
For lngN2 = lngLower To lngUpper
lngI = lngN2 - lngLower
For lngN1 = LBound(varArray2D, 1) To UBound(varArray2D, 1)
lngJ = lngN1 - LBound(varArray2D, 1)
varArray2D(lngN1, lngN2) = varNewArray2D(lngJ, lngI)
Next
Next
Case Else
End Select
End Sub
'******************************************************************************
'処 理:2次元配列を並び替え範囲で縮小し、昇順に並び替える(マージソート)
'
'戻 り 値:次元1の0番を基準に昇順で並び変えた2次元配列(並び替え範囲外は除外)
'
'引 数:varTgtArray2D - 2次元配列
' lngTgtLower - 並び替え範囲下限の添字(INDEX)
' lngTgtUpper - 並び替え範囲上限の添字
'
'備 考:MergeSort2D専用の関数1/2
'
Function MergeSortedArray2D(ByRef varTgtArray2D, ByVal lngTgtLower _
, ByVal lngTgtUpper)
Dim lngTgtRange, lngSep, lngI, lngJ, lngN1, lngN2, lngLZ, lngRZ
Dim varLeftArray, varRightArray, varTempArray
lngTgtRange = lngTgtUpper - lngTgtLower
If lngTgtRange = 0 Then
ReDim varTempArray(1, 0)
varTempArray(0, 0) = varTgtArray2D(0, lngTgtLower)
varTempArray(1, 0) = varTgtArray2D(1, lngTgtLower)
MergeSortedArray2D = varTempArray
Exit Function
ElseIf lngTgtRange <= 20 Then '閾値以下で挿入ソートを実行
MergeSortedArray2D = InsertionSortedArray2D(varTgtArray2D _
, lngTgtLower, lngTgtUpper)
Exit Function
Else 'マージソートを実行
lngSep = Int((lngTgtLower + lngTgtUpper) / 2)
varLeftArray = MergeSortedArray2D(varTgtArray2D, lngTgtLower, lngSep)
varRightArray _
= MergeSortedArray2D(varTgtArray2D, lngSep + 1, lngTgtUpper)
ReDim varTempArray(1, lngTgtRange)
lngI = 0: lngJ = 0
lngLZ = UBound(varLeftArray, 2): lngRZ = UBound(varRightArray, 2)
For lngN1 = 0 To lngTgtRange
If lngJ > lngRZ Then '右の配列が終わった時
For lngN2 = lngN1 To lngTgtRange '左の配列の残り全部を代入
varTempArray(0, lngN2) = varLeftArray(0, lngI)
varTempArray(1, lngN2) = varLeftArray(1, lngI)
lngI = lngI + 1
Next
Exit For
ElseIf lngI > lngLZ Then '左の配列が終わった時
For lngN2 = lngN1 To lngTgtRange '右の配列の残り全部を代入
varTempArray(0, lngN2) = varRightArray(0, lngJ)
varTempArray(1, lngN2) = varRightArray(1, lngJ)
lngJ = lngJ + 1
Next
Exit For
ElseIf varLeftArray(0, lngI) <= varRightArray(0, lngJ) Then
varTempArray(0, lngN1) = varLeftArray(0, lngI)
varTempArray(1, lngN1) = varLeftArray(1, lngI)
lngI = lngI + 1
Else
varTempArray(0, lngN1) = varRightArray(0, lngJ)
varTempArray(1, lngN1) = varRightArray(1, lngJ)
lngJ = lngJ + 1
End If
Next
MergeSortedArray2D = varTempArray
End If
End Function
'******************************************************************************
'処 理:2次元配列を並び替え範囲で縮小し、昇順に並び替える(挿入ソート)
'
'戻 り 値:次元1の0番を基準に昇順で並び変えた2次元配列(並び替え範囲外は除外)
'
'引 数:varTgtArray2D - 2次元配列
' lngTgtLower - 並び替え範囲下限の添字(INDEX)
' lngTgtUpper - 並び替え範囲上限の添字
'
'備 考:MergeSort2D専用の関数2/2
'
Function InsertionSortedArray2D(ByRef varTgtArray2D, ByVal lngTgtLower _
, ByVal lngTgtUpper)
Dim lngI, lngJ, varTemp0, varTemp1, varTempArray, lngTgtRange
lngTgtRange = lngTgtUpper - lngTgtLower
ReDim varTempArray(1, lngTgtRange)
For lngI = 0 To lngTgtRange
varTempArray(0, lngI) = varTgtArray2D(0, lngTgtLower + lngI)
varTempArray(1, lngI) = varTgtArray2D(1, lngTgtLower + lngI)
Next
For lngI = 1 To lngTgtRange
varTemp0 = varTempArray(0, lngI) '基準値
varTemp1 = varTempArray(1, lngI)
For lngJ = lngI - 1 To 0 Step -1
If varTempArray(0, lngJ) <= varTemp0 Then Exit For
varTempArray(0, lngJ + 1) = varTempArray(0, lngJ) '老番へ1移動
varTempArray(1, lngJ + 1) = varTempArray(1, lngJ)
Next
varTempArray(0, lngJ + 1) = varTemp0 '基準値を挿入
varTempArray(1, lngJ + 1) = varTemp1
Next
InsertionSortedArray2D = varTempArray
End Function
'******************************************************************************
'処 理:2次元配列のデータをメッセージ表示用の文字列に変換する
'
'戻 り 値:メッセージ表示用の文字列
'
'引 数:strArray2D - 2次元配列
' boolCS - True = 列間をカンマ区切り、False = 列間をTab区切り
' boolVertical - True = 2番目の次元を縦表示、False = 横表示
'
'備 考:配列の要素数が行列数の上限を超えた分は残りを省略
'
Function ConfirmationTextForArray2D(ByRef strArray2D, ByVal boolCS _
, ByVal boolVertical)
Dim intN1, intN2, strTemp, strSeparate, intD1, intD2
Const c_intIy = 10 '行数の上限
Const c_intIx = 10 '列数の上限
If boolCS = True Then
strSeparate = "," 'カンマ区切り
Else
strSeparate = Chr(9) 'Tab区切り
End If
If boolVertical = True Then
intD1 = 1: intD2 = 2 '2番目の次元を縦表示にする変数設定
Else
intD1 = 2: intD2 = 1 '2番目の次元を横表示にする変数設定
End If
For intN2 = LBound(strArray2D, intD2) To UBound(strArray2D, intD2)
If intN2 > LBound(strArray2D, intD2) Then
strTemp = strTemp & vbCrLf '改行の追加
End If
If c_intIy >= 1 And intN2 >= c_intIy + LBound(strArray2D, intD2) Then
strTemp = strTemp & "他" & UBound(strArray2D, intD2) _
- (c_intIy - 1) & "行" '行数上限超過の処理
Exit For
End If
For intN1 = LBound(strArray2D, intD1) To UBound(strArray2D, intD1)
If intN1 > LBound(strArray2D, intD1) Then
strTemp = strTemp & strSeparate '区切り文字の追加
End If
If c_intIx >= 1 _
And intN1 >= c_intIx + LBound(strArray2D, intD1) Then
If intN2 = LBound(strArray2D, intD2) Then
strTemp = strTemp & "他" & UBound(strArray2D, intD1) _
- (c_intIx - 1) & "列" '列数上限超過の処理
End If
Exit For
Else
If boolVertical = True Then
strTemp = strTemp & "配列(" & intN1 & ", " & intN2 _
& ") = " & strArray2D(intN1, intN2)
Else
strTemp = strTemp & "配列(" & intN2 & ", " & intN1 _
& ") = " & strArray2D(intN2, intN1)
End If
End If
Next
Next
ConfirmationTextForArray2D = strTemp
End Function
上記のコードを Windows 10 のアクセサリから開いたメモ帳へコピー&ペースト後、文字コードを「ANSI」に設定し、適当なファイル名に拡張子「.vbs」をつけてデスクトップ等に保存すると、すぐに動作確認できます。
保存した vbsファイルをダブルクリックすると、要素数3×16,384の配列をランダムの整数値で作成後、データの並び替えが1番目の次元の老番から基準に2、1、0と3回行われ、昇順でソートされた配列の若番から10×3の要素と、配列を3回ソートした時間(秒)がメッセージで表示されます。
これを Microsoft Excel のワークシートの配列で例えると、ワークシートの上から3行を端から端までランダムの整数値で埋め尽くした後、選択範囲を拡張した昇順の並び替えを横方向に3行目、2行目、1行目と3回実行している状態です。
このソートは安定ソートなので、1列目の要素が重複していた場合、2列目はかならず昇順で表示されます。
解説
4~10行目は要素数3×16,384の配列を0~49,151の範囲のランダムの整数値で作成しています。
11行目は Timer関数でソート前の基準の秒数を取得しています。
12~14行目は20行目のアスタリスク(*)以下に記載しているプロシージャを使って配列varArray を1番目の次元の老番から順番に 2、1、0 を基準として昇順でソートしています。
このプロシージャはソートする範囲を指定できますが、今回は全てソートするので、並び替え範囲下限を0、上限を配列の添字の上限にしています。並び替え範囲は2番目の次元になるので、引数intDimention を 2 に設定しています
15~16行目は230行目のアスタリスク(*)以下に記載している2次元配列のデータをメッセージ表示用の文字列で返すファンクション(関数)を使ってソート後の配列を表示すると同時に、Timer関数を使ってソート時間を表示しています。
20~129行目は2次元配列のデータを昇順に並び替えるプロシージャです。このプロシージャの主な機能は引数不正の検知、並べ替える要素とソートする前の添字の2次元配列の作成、ファンクションによる並び替え、最後にソートする前の添字を参照した並び替え後の配列作成です。
プロシージャの名前は「MergeSort2D」となっていますが、マージソートのアルゴリズムを一切含んでいません。
36~70行目は引数の不正の検出と並べ替える要素と、ソートする前の添字の2次元配列を作成しています。
引数の不正を検出すると「Error 13」の記述によりメッセージボックスでエラーが表示され、プログラムが中断します。
ソートする前の添字の配列は、2次元配列でソートしない方向の要素数が3以上のときに、入れ替え回数を減らすのに必要です。
72行目は130行目のアスタリスク(*)以下に記載しているファンクションで、ソートされた要素と、ソートする前の添字で構成された2次元配列の変数を代入しています。
このファンクションの名前を「MergeSortedArray2D」から「InsertionSortedArray2D」に記述を替えると純粋な挿入ソートになりますが、このサンプルコードで作成しているような1万を超えるデータで挿入ソートを実行すると、処理に時間がかかりすぎるのでお勧めできません。
74~96行目はソートされた2次元配列の要素にある、ソートする前の添字を参照して、ソートされた位置へ配列の要素を代入しています。
97~107行目は配列varArray が0から始まる配列でソート範囲が配列全体だった場合、配列varArray にソートされた配列を一括で代入してプロシージャを終了します。
ただし、引数の変数が配列として宣言されていた場合は、配列の変数を一括で代入するとエラーが発生するので、110行目以降の処理に移行します。
110~128行目は配列varArray にソートされた配列を1つずつ代入しています。最後まで代入すると指定された範囲をソートした配列が完成します。
130~192行目は2次元配列のデータを「マージソート」するファンクションです。
147行目は153行目の挿入ソートを停止した時に実行されますが、挿入ソートを併用しているときは実行されません。
153行目は挿入ソートを実行する条件です。サンプルコードでは配列の数が20以下で挿入ソートが実行されます。この閾値の条件を「lngTgtRange < 0」にすると全てマージソートのみで処理されます。
しかし、このプログラムは閾値以下で挿入ソートに切り替えることを前提とした設計になっているため、配列の数によっては最後の分割で端数が発生しやすくなるので処理の効率が悪くなります。
よって、挿入ソートを停止した場合、純粋なマージソートよりも処理速度が若干遅くなります。
158~161行目は引数の配列を左右に分割して、自身のファンクション(再帰関数)を使ってソートしています。
162行目は並び替え範囲に縮小した一時保管の配列を作成しています。配列の範囲を縮小するとソートの時間を短縮できます。
163~189行目は左右の配列を若番から順に値を比較して、一時保管の配列に並べています。
190行目は戻り値に一時保管配列を代入しています。
193~229行目は2次元配列のデータを「挿入ソート」するファンクションです。(2021/04/15 ソートの時間を短縮する為、一部改修)
208~213行目は並び替え範囲の値だけを抽出して一時保管の配列を作成しています。配列の範囲を縮小するとソートの時間を短縮できます。
214~227行目は挿入ソートで一時保管の配列を並び替えています。
228行目は戻り値に一時保管配列を代入しています。
230行目のアスタリスク(*)以下に記載しているファンクションは【VBScript】プロシージャとファンクション(関数)の使い方で紹介したものを2次元配列用にアレンジしたものです。
引数の説明にも記載してありますが、2番目の引数を True に変更すると列間がカンマ区切りになり、3番目の引数を False に変更すると縦横が逆転します。
サンプルコードで使用しているプロシージャとファンクションは Excel等の VBAでも動作します。
2次元配列を1番目の次元の範囲で昇順に並び替える(安定ソート)
サンプルコード
2次元配列を1番目の次元の範囲(Microsoft Excel のワークシートの配列では縦方向)で昇順に並び替える場合も同じプロシージャを使います。
並び替えテスト用の配列のサイズとプロシージャの引数、メッセージボックスで使用しているファンクションの引数の設定だけ変わります。プロシージャの手前までのプログラムは次のとおりです。
Option Explicit
Dim varArray, sngTime, lngN1, lngN2
ReDim varArray(65535, 2)
For lngN1 = LBound(varArray, 1) To UBound(varArray, 1)
For lngN2 = LBound(varArray, 2) To UBound(varArray, 2)
varArray(lngN1, lngN2) = Int(Rnd * ((UBound(varArray, 1) + 1) _
* (UBound(varArray, 2) + 1) + 1))
Next
Next
sngTime = Timer
Call MergeSort2D(varArray, 0, 65535, 1, 2)
Call MergeSort2D(varArray, 0, 65535, 1, 1)
Call MergeSort2D(varArray, 0, 65535, 1, 0)
MsgBox ConfirmationTextForArray2D(varArray, False, False), , _
"並び替え処理の時間(秒):" & Round(Timer - sngTime, 3)
WScript.Quit
上記のコードを利用するには、まず、「2次元配列を2番目の次元の範囲で昇順に並び替える(安定ソート)」で紹介したサンプルコードをWindows 10 のアクセサリから開いたメモ帳へコピー&ペースト後、最初のアスタリスクから上の部分を、上記のコードのコピー&ペーストで置き換えます。
文字コードを「ANSI」に設定し、適当なファイル名に拡張子「.vbs」をつけてデスクトップ等に保存すると、すぐに動作確認できます。
保存した vbsファイルをダブルクリックすると、要素数65,536×3の配列をランダムの整数値で作成後、データの並び替えが2番目の次元の老番から基準に2、1、0と3回行われ、昇順でソートされた配列の若番から10×3の要素と、配列を3回ソートした時間(秒)がメッセージで表示されます。
これを Microsoft Excel のワークシートの配列で例えると、ワークシートの左から3列を1~65,536行目までランダムの整数値で埋め尽くした後、選択範囲を拡張した昇順の並び替えを縦方向に3列目、2列目、1列目と3回実行している状態です。
このソートは安定ソートなので、1列目の要素が重複していた場合、2列目は必ず昇順で表示されます。
解説
4~10行目は要素数65,536×3の配列を0~196,607の範囲のランダムの整数値で作成しています。
今回は1番目の次元のソートなので、1番目の次元の要素の数を増量しています。
11行目は Timer関数でソート前の基準の秒数を取得しています。
12~14行目は最初のサンプルコードで紹介したプロシージャを使って配列varArray を2番目の次元の老番から順番に2、1、0を基準として昇順でソートしています。引数は並び替え範囲上限の添字 lngUpper を 65,535、並び替えの基準となる添字 intDimention を 1 に変更しています。
15~16行目は最初のサンプルコードで紹介した、2次元配列のデータをメッセージ表示用の文字列で返すファンクション(関数)を使ってソート後の配列を表示すると同時に、Timer関数を使ってソート時間を表示しています。表示する配列は縦長になるので、引数boolVertical を False に変更しています。
まとめ
- 2次元配列は不安定ソートで重複データを並び替えた時に、別の項目の順番が崩れる可能性がある
- 2次元配列の重複データを含む並び替えは安定ソート推奨
- 2次元配列は並び替える要素以外の全ての要素を並び替える前の添字(ソート以前のINDEX)に置き換えると、ソートしない方向の要素数が3以上のときに入れ替え回数が減る
- 配列のデータが多いときはマージソート、配列の分割でデータが少なくなったときに挿入ソートへ切り替えると、短時間で並び替える安定ソートになる
- 1万を超えるデータは挿入ソートを実行すると、処理に時間がかかりすぎる
- 引数の変数が配列として宣言されていた場合、配列の変数を一括で代入するとエラーが発生する
- ソートアルゴリズムは配列の範囲を縮小するとソートの時間を短縮できる
ありがとうございました。


コメント