0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

第11回 直感!スグに使える業務向けVBA汎用プロシージャ(配列内ソート)

Last updated at Posted at 2025-06-16

Ver.1.2.xリリースいたしました!(Ver.1.1.0は諸事情によりお蔵入り…)

以下のプロシージャを新規で追加しました、今回は開発するシステムの堅牢性を向上させることを目的としたプロシージャを多数作ってみました。
まだまだ作りたいものはありますのでのんびり作っていきたいと思います。

プロシージャ名 概要
SortArray 1次元配列の内容を昇順または降順にソート
ShowAllCells 対象シートの全行・前列を表示
AutoCellToArray 対象シートのセルの内容を自動で配列に変換
GetDataArea シートのデータ範囲のアドレスを自動取得
AutoDeleteBlankRows / AutoDeleteBlankColumns 空白行/列を削除
GetFiscalYear / ToWareki 日付表記処理
KanaConv / AtoZConv / NumConv 全角⇔半角変換
FileSafe / SheetSafe 禁則文字を代替文字に変換
MoveItem ファイル移動、必要により元フォルダにショートカット生成
ConvertOneDrivePath OneDrive上のパスを物理ディレクトリに変換
以下のリンクから .bas ファイルをダウンロードできます(zipファイル)

さて、今回紹介するプロシージャは

プロシージャ名 概要
SortArray 1次元配列の内容を昇順または降順にソート

業務においてデータをソートすることってよくありますよね、今回1次元配列限定ではありますが配列の中身を昇順または降順にソートができ、さらに入力の配列の規模によって適したソート方法を自動で切り替えるというプロシージャを(ChatGPTの力を借りながら)作ってみました。

SortArray

Function SortArray(originalArray As Variant, Optional sortMethod As Long = 1) As Variant
'------------------------------------------------------------------------------------------------------------------------------
' 概要  |1次元配列を昇順または降順でソート(配列規模によってソート方法を自動で変更)
'------------------------------------------------------------------------------------------------------------------------------
' 引数1 |originalArray - ソート対象の1次元配列
' 引数2 |sortMethod - ソート方法(1:昇順,2:降順,デフォルトは1)(Long型)
'------------------------------------------------------------------------------------------------------------------------------
' 戻り値 |Variant型 - ソート済み1次元配列(インデックスは1開始)
'------------------------------------------------------------------------------------------------------------------------------
' 実装  |Ver.1.1.0(2025/06/14:新規)
'     |Ver.1.2.0(2025/06/16:大規模データに対し自動でマージソートを適用する機能を追加)
'------------------------------------------------------------------------------------------------------------------------------
    
    'ユーザー定義エラー
    If IsArray(originalArray) <> True Then
        Err.Raise vbObjectError + 1001, "SortArray", "引数は1次元配列を指定してください"
    End If
    If sortMethod <> 1 And sortMethod <> 2 Then
        Err.Raise vbObjectError + 1002, "SortArray", "引数は1(昇順)または2(降順)にしてください"
    End If
    
    Dim iLoop           As Long 'ループカウンタ
    Dim jLoop           As Long 'ループカウンタ
    Dim kLoop           As Long 'ループカウンタ
    Dim elemCount       As Long '空白を考慮した配列要素数
    Dim halfNum         As Long '配列要素数÷2
    Dim leftArr()       As Variant '分割後配列
    Dim rightArr()      As Variant '分割後配列
    Dim mergedArr()     As Variant '結合用配列
    Dim tempNumber      As Variant '要素入れ替え用変数
    
    '要素数の取得
    elemCount = UBound(originalArray) - LBound(originalArray) + 1
    
    '要素数が0または1の場合そのままの値を返す
    If elemCount <= 1 Then
        SortArray = originalArray
        Exit Function
    End If
    
    Select Case True
        'バブルソートを適用
        Case elemCount <= 50
            Select Case sortMethod
                '昇順にソート
                Case 1
                    For iLoop = LBound(originalArray) To UBound(originalArray) - 1
                        For jLoop = iLoop + 1 To UBound(originalArray)
                            If originalArray(iLoop) > originalArray(jLoop) Then
                                tempNumber = originalArray(iLoop)
                                originalArray(iLoop) = originalArray(jLoop)
                                originalArray(jLoop) = tempNumber
                            End If
                        Next
                    Next iLoop
                '降順にソート
                Case 2
                    For iLoop = LBound(originalArray) To UBound(originalArray) - 1
                        For jLoop = iLoop + 1 To UBound(originalArray)
                            If originalArray(iLoop) < originalArray(jLoop) Then
                                tempNumber = originalArray(iLoop)
                                originalArray(iLoop) = originalArray(jLoop)
                                originalArray(jLoop) = tempNumber
                            End If
                        Next
                    Next iLoop
            End Select
            
            SortArray = originalArray
        'マージソートを適用
        Case elemCount > 50
            '元配列の分割
            halfNum = elemCount \ 2
            ReDim leftArr(1 To halfNum)
            ReDim rightArr(1 To elemCount - halfNum)
            
            For iLoop = 1 To halfNum
                leftArr(iLoop) = originalArray(LBound(originalArray) + iLoop - 1)
            Next iLoop
            For iLoop = 1 To elemCount - halfNum
                rightArr(iLoop) = originalArray(LBound(originalArray) + halfNum + iLoop - 1)
            Next iLoop
            
            '再帰ソート
            leftArr = SortArray(leftArr, sortMethod)
            rightArr = SortArray(rightArr, sortMethod)
            
            '配列の結合
            ReDim mergedArr(1 To elemCount)
            iLoop = 1
            jLoop = 1
            kLoop = 1
            Do While iLoop <= UBound(leftArr) And jLoop <= UBound(rightArr)
                Select Case sortMethod
                    '昇順にソート
                    Case 1
                        If leftArr(iLoop) <= rightArr(jLoop) Then
                            mergedArr(kLoop) = leftArr(iLoop)
                            iLoop = iLoop + 1
                        Else
                            mergedArr(kLoop) = rightArr(jLoop)
                            jLoop = jLoop + 1
                        End If
                    '降順にソート
                    Case 2
                        If leftArr(iLoop) > rightArr(jLoop) Then
                            mergedArr(kLoop) = leftArr(iLoop)
                            iLoop = iLoop + 1
                        Else
                            mergedArr(kLoop) = rightArr(jLoop)
                            jLoop = jLoop + 1
                        End If
                End Select
                kLoop = kLoop + 1
            Loop
            
            Do While iLoop <= UBound(leftArr)
                mergedArr(kLoop) = leftArr(iLoop)
                iLoop = iLoop + 1
                kLoop = kLoop + 1
            Loop
            Do While jLoop <= UBound(rightArr)
                mergedArr(kLoop) = rightArr(jLoop)
                jLoop = jLoop + 1
                kLoop = kLoop + 1
            Loop
            
            SortArray = mergedArr
    End Select
    
End Function

本プロシージャはバブルソートという方法とマージソートという2つの方法を採用しております。ソートのアルゴリズムに関しては省略させていただきますが、ざっくりバブルソートは小規模データ向き、マージソートは大規模データ向きを覚えていただければ十分です!この記事のためにソートのアルゴリズムについても調べましたが、いろいろあるんですね…勉強になりました。

クイックソートやマージソートといった手法は少ない手数でソートを完了できるという点が強みではありますが、アルゴリズムの都合上メモリに負荷がかかるため小規模データであればソートの手数は多いですが、バブルソートのようなシンプルなアルゴリズムのほうが良かったりするのだそうです。
「だったらデータの規模を自動で判断させて適切なアルゴリズムを適用してもらえばユーザーは楽なのでは?」というものぐさな発想のもと生まれたのがこのプロシージャです(笑)

動作解説

サンプルプログラムとその動作結果を示します、配列aに対して昇順と降順のソートをかけてみました。

Sub Main()
    
    Dim a As Variant '元配列
    Dim b As Variant '昇順
    Dim c As Variant '降順
    Dim i As Long 'ループカウンタ
    
    a = Array(1, "あいうえお", 5, 3, 8, "かきくけこ", 6, 9, 0)
    b = SortArray(a, 1)
    c = SortArray(a, 2)
    
    Debug.Print "昇順ソート"
    For i = LBound(a) To UBound(a)
        Debug.Print b(i)
    Next i
    
    Debug.Print "------------------"
    Debug.Print "降順ソート"
    For i = LBound(a) To UBound(a)
        Debug.Print c(i)
    Next i
    
End Sub

こちらのサンプルに対する出力は以下のようになります。

Excel-11-1.png

ぜひ用途に合わせて使ってみてください!ソートや配列に関してまたアイデアが浮かんできましたら順次追加していこうと思います!

直感!VBAシリーズ記事一覧

もしよろしければ他の記事もご覧ください!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?