ExcelマクロVBAサンプル集 | 2次元配列の並べ替え(バブルソート,クイックソート) | Excelマクロの実用サンプル、エクセルVBA集と解説



最終更新日:2013-09-05

2次元配列の並べ替え(バブルソート,クイックソート)


配列(2次元)の並べ替え方法について、バブルソートとクイックソートのサンプルになります。

2次元配列の並べ替えと言えば、まさにワークシートの並べ替え機能になります。


本来は、ワークシートにデータを書き出して、ワークシートの並べ替え機能を使えば良いのですが、

しかし、どうしても、配列をワークシートに処理途中で書き出すと言うのは面倒なものです。

そこで、2次元配列を並べ替える必要が出てきます。

以下では、

Sheet1A1〜B10000にランダムなデータを入れました。

これを(昇順に)並べ替えて、Sheet2 に出力しています。

1次元配列の並べ替えについては、以下を参照して下さい。

1次元配列の並べ替え(バブルソート,クイックソート)

VBAコードはほぼ1次元配列と同様になりますが、

キー位置(インデックス)を指定できるようにしています。

バブルソート

ソートのアルゴリズムの中で、簡単で理解しやすいのは、バブルソートでしょう 。

バブルは「泡」のことで、並べ替えの過程でデータが下から上へ移動する感じが、泡が浮かんでいく様に見えることからこの名前が付いています。
Sub BubbleSort2(ByRef argAry() As Variant, ByVal keyPos As Long)
  Dim vSwap
  Dim i As Integer
  Dim j As Integer
  Dim k As Integer
  For i = LBound(argAry, 1) To UBound(argAry, 1)
    For j = UBound(argAry, 1) To i Step -1
      If argAry(i, keyPos) > argAry(j, keyPos) Then
        For k = LBound(argAry, 2) To UBound(argAry, 2)
          vSwap = argAry(i, k)
          argAry(i, k) = argAry(j, k)
          argAry(j, k) = vSwap
        Next
      End If
    Next j
  Next i
End Sub

外側のFor〜Nextの1回目が終わった時点で、配列の先頭に最小値が来ます。
以下、2回目のループで配列の2番目に2番目に小さいデータが来ます。
これの繰り返しになっています。

If argAry(i) > argAry(j) Then
これを
If argAry(i) < argAry(j) Then
とすれば、降順の並べ替えになります。

KeyPosが、並べ替えのキー位置(インデックス)になります。

非常に単純ですが、処理時間がかかる事が難点です。
データ件数が、多くなければ単純で良いでしょう。

では、実際の使い方と、その処理時間を見てみます。
Sub test3() '10秒
  Debug.Print Timer
  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Dim myAry1()
  Dim i As Long
  Set ws1 = Worksheets("Sheet1")
  Set ws2 = Worksheets("Sheet2")
  myAry1 = ws1.Range("A1:B10000").Value
  '2次元バブルソート
  Call BubbleSort2(myAry1, 1)
  ws2.Cells.Clear
  ws2.Range("A1:B10000").Value = myAry1
  Debug.Print Timer
End Sub

私の環境で 約24秒かかりました。

1万件で24秒・・・ちょっと使うには厳しいですね。

Call BubbleSort2(myAry1, 1)

この第二引数の数値がキー位置のインデックスになっています。

では、もっと効率の良いソートアルゴリズムはないのか・・・

それがクイックソートになります。

クイックソート

クイックソートは一般的に最も高速だといわれてはいます。

アルゴリズムとしてはいろいろな亜種があるらしいです。

ここでは、ごく一般的な方法を採用しています。

アルゴリズムの詳細は、説明が長くなってしまいますので、専門に解説しているページを参照して下さい。
Sub QuickSort2(ByRef argAry() As Variant, ByVal lngMin As Long, ByVal lngMax As Long, ByVal keyPos As Long)
  Dim i As Long
  Dim j As Long
  Dim k As Long
  Dim vBase As Variant
  Dim vSwap As Variant
  vBase = argAry(Int((lngMin + lngMax) / 2), keyPos)
  i = lngMin
  j = lngMax
  Do
    Do While argAry(i, keyPos) < vBase
      i = i + 1
    Loop
    Do While argAry(j, keyPos) > vBase
      j = j - 1
    Loop
    If i >= j Then Exit Do
    For k = LBound(argAry, 2) To UBound(argAry, 2)
      vSwap = argAry(i, k)
      argAry(i, k) = argAry(j, k)
      argAry(j, k) = vSwap
    Next
    i = i + 1
    j = j - 1
  Loop
  If (lngMin < i - 1) Then
    Call QuickSort2(argAry, lngMin, i - 1, keyPos)
  End If
  If (lngMax > j + 1) Then
    Call QuickSort2(argAry, j + 1, lngMax, keyPos)
  End If
End Sub

このアルゴリズムをすっきり理解するのは大変ですね。

検索時の二分探索と同じような考え方と言えば良いでしょうか。

配列の中央値との大小比較を行い、取り替える。

これを再帰プロージャーで、範囲を狭めながら繰り返しています。

これにより並べ替えを実現しています。

では、実際の使い方と、その処理時間を見てみます。

Sub test4() '0.23
  Debug.Print Timer
  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Dim myAry1()
  Dim i As Long
  Set ws1 = Worksheets("Sheet1")
  Set ws2 = Worksheets("Sheet2")
  myAry1 = ws1.Range("A1:B10000").Value
  '2次元クイックソー
  Call QuickSort2(myAry1, LBound(myAry1), UBound(myAry1), 1)
  ws2.Cells.Clear
  ws2.Range("A1:B10000").Value = myAry1
  Debug.Print Timer
End Sub

私の環境で 約0.28秒です。

やはり断然はやいですね。

数百件程度の配列なら、バブルソートでもよいですが、

それ以上になるなら、やはりクイックソートが好ましいでしょう。

今回は2次元配列として紹介しましたが、

ユーザー定義型(構造体)の1次元配列とした方が良いのではないかと思います。

もちろんデータ内容にもよりますので、構造体にするのが大変な場合は別です。

ですが、大抵のデータ構造は、構造体を使う事でデータ構造を明示でき、

かつ、このような並べ替えにおいても、1次元配列として扱えるようになります。

構造体については、第110回.ユーザー定義型(構造体)Type

複数キーでの並べ替えについて

最も簡単な方法が、複数キーを1つに繋げたキーを作成する方法になります。

キーをつなげて、1つのキーとして扱います。

この時注意するのは、桁数です。

Key1 > Key2

で、数値の場合なら、

Format(Key1, "00000") & Format(Key1, "00000")

このように桁数を一致させて結合します。

もちろん、必要な最大桁数を指定します。

文字列なら、桁数が揃うように、後ろに半角スペースを入れます。

Key1 & Space(30 - Len(Key1)) & Key2 & Space(30 - Len(Key2))

こんな感じです。

これをソートキーとすることで複数キーの並べ替えが可能です。

ワークシートを使って並べ替え・・・番外編

最期に、ワークシートを使って2次元配列を並べ替えするプロシージャーを紹介します。

Excel.Applicationのインスタンツを作成し、非表示Excel内で並べ替えを行います。

Sub SheetSort(ByRef argAry() As Variant, ByVal keyPos As Long)
  Dim wb As Workbook
  Dim ws As Worksheet
  Dim rng As Range
  Dim xlApp As New Excel.Application
  Set wb = xlApp.Workbooks.Add
  Set ws = wb.ActiveSheet
  With ws
    Set rng = .Range(.Cells(LBound(argAry, 1), LBound(argAry, 2)), .Cells(UBound(argAry, 1), UBound(argAry, 2)))
    rng.Value = argAry
    rng.Sort Key1:=.Cells(1, keyPos), Order1:=xlAscending, Header:=xlNo
    argAry = rng.Value
    
  End With
  wb.Close SaveChanges:=False
  Set xlApp = Nothing
End Sub

上記は、LBoundが1であることを前提にしています。

LBoundが0の場合は、1を足し引きする部分の追加が必要になります。

では、使い方です。

Sub test5()
  Debug.Print Timer
  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Dim myAry1()
  Dim i As Long
  Set ws1 = Worksheets("Sheet1")
  Set ws2 = Worksheets("Sheet2")
  myAry1 = ws1.Range("A1:C10000").Value
  'シートでソート
  Call SheetSort(myAry1, 2)
  ws2.Cells.Clear
  ws2.Range("A1:C10000") = myAry1
  Debug.Print Timer
End Sub

私の環境で 約0.91秒です。

Excelインスタンスを生成し、ブックの追加をしている事を考えれば、

予想以上に速いですね。

つまり、ワークシートの並べ替えが非常に高速である事の証になります。

従って、作業中のワークシートで並べ替えが可能ならば、それが最も良いと言う事になります。





同じテーマ「ExcelマクロVBAサンプル集」の記事

Dir関数で全サブフォルダの全ファイルを取得
1次元配列の並べ替え(バブルソート,クイックソート)

新着記事 ・・・新着記事一覧を見る

最後の空白(や指定文字)以降の文字を取り出す|エクセル関数超技(3月26日)
先頭の数値、最後の数値を取り出す|エクセル関数超技(3月26日)
Excelファイルを開かずにシート名をチェック|ExcelマクロVBAサンプル集(3月23日)
数式の参照しているセルを取得する|ExcelマクロVBAサンプル集(3月18日)
CSVの読み込み方法(改の改)|ExcelマクロVBAサンプル集(3月17日)
変数とプロシージャーの命名について|ExcelマクロVBA技術解説(2月12日)
ファイルの一覧取得・削除(File)|Google Apps Script入門(1月24日)
フォルダの一覧取得・作成・削除(Folder)|Google Apps Script入門(1月24日)
フォルダとファイルを扱う(DriveApp)|Google Apps Script入門(1月24日)
スプレッドシートが非常に遅い、高速化するには|Google Apps Script入門(1月17日)

アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|ExcelマクロVBA入門
2.RangeとCellsの使い方|ExcelマクロVBA入門
3.徹底解説(VLOOKUP,MATCH,INDEX,OFFSET)|エクセル関数超技
4.Range以外の指定方法(Cells,Rows,Columns)|ExcelマクロVBA入門
5.セルの参照範囲を可変にする(OFFSET,COUNTA,MATCH)|エクセル関数超技
6.セルのコピー&値の貼り付け(PasteSpecial)|ExcelマクロVBA入門
7.変数とデータ型(Dim)|ExcelマクロVBA入門
8.ひらがな⇔カタカナの変換|エクセル基本操作
9.CSVの読み込み方法|ExcelマクロVBAサンプル集
10.VBAのFindメソッドの使い方には注意が必要です|ExcelマクロVBA技術解説



  • >
  • >
  • >
  • 2次元配列の並べ替え(バブルソート,クイックソート)

  • このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


    記述には細心の注意をしたつもりですが、
    間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
    なお、掲載のVBAコードは自己責任で使ってください。万一データ破損等の損害が発生しても責任は負いません。

    ↑ PAGE TOP