GEN MUTO'S HOMEPAGE  エクセル大事典  エクセルVBAを極める

エクセルExcel大事典 エクセル大事典TOPページへ
 ■ エクセルVBA中級編−VBAでいろんなテクニック
  並べ替え(ソート)をマスターしよう!
 
■ 並べ替え(ソート)をマスターしよう!

ExcelVBAには、組み込みソート関数が存在しません。その代りに強力なRangeオブジェクトのSortメソッドが用意されています。これほど強力なソートメソッド(ソート機能)が用意されているプログラミング言語は他にはないでしょう。

このSortメソッドを使えば、2次元の配列をいとも簡単に複数Key指定し、望み通りの順番に並べ替えることが可能です。しかも、そのスピードはVBAではありえないほど高速です。このSortメソッドは本来、エクセルのネイティブな機能として用意されている「並べ替え」をVBAから利用するために用意されているメソッドです。つまり、Excelのもつ並べ替えの機能自体が驚くほど高速であるといえます。

ただしこのSortメソッドの並べ替えを利用する場合、シート上にあるデータ以外については、いったんワークシートにデータを格納する必要があります。さらに並べ替えの結果をワークシートから取得し、元の配列に格納し直す必要があります。そのハンデを考慮しても、このSortメソッドを利用する価値は十分にあります。

そしてせっかくVBAを利用しているので、一般的なソート関数(ユーザー関数)やADOレコードセットオブジェクトを利用した並べ替えなど、さまざまなテクニックを知っておいたほうが、いろいろなケースで応用できて便利でしょう。

さっそく、ソート(並べ替え)テクニックを解説していきましょう。

RangeオブジェクトのSortメソッドによる並べ替え
(例)
Public Sub test()
Dim i As Long
Dim MyLng() As Long
Dim MyRngSet As Range
Dim MyRngGet As Variant
Const CstLng As Long = 10
  ReDim MyLng(1 To CstLng, 0)
  For i = 1 To UBound(MyLng)
    MyLng(i, 0) = Int(Rnd * UBound(MyLng))
  Next i
  Set MyRngSet = Range("A1:A" & UBound(MyLng))
    MyRngSet = MyLng
  MyRngSet.Sort Key1:=Range("A1")
  MyRngGet = MyRngSet
  For i = 1 To UBound(MyLng)
    MyLng(i, 0) = MyRngGet(i, 1)
  Next i
End Sub
この例では、配列MyLngに10個の要素の乱数を格納し、アクティブシートのセル範囲A1:A10にセットします。MyRngSet.Sort Key1:=Range("A1") の部分でセル範囲をソートした後、元の配列MyLngに格納しなおしています。
※ CstLngの値を変えると、並べ替える配列の要素数の上限を変更できます。

Sortメソッドには、たくさんの引数があります。ヘルプでは全ての引数は省略可能となっていますが、Key1の引数を省略すると実行時エラー'1004' RangeクラスのSortメソッドが失敗しました。のエラーが発生します。

  MyRngSet.Sort _
    Key1:=Range("A1"), _
    Order1:=xlAscending, _
    Header:=xlGuess, _
    OrderCustom:=1, _
    MatchCase:=False, _
    Orientation:=xlTopToBottom, _
    SortMethod:=xlPinYin, _
    DataOption1:=xlSortNormal

各引数はこのようになっています。2次元配列の場合、3つまでKeyを指定することが可能です。その場合は、Key2:= 、Order2:= のように記述を追加します。
Key Key項目として利用するフィールドのテキストまたはRangeオブジェクトを指定します。
Order xlAscending (既定値) で昇順に、xlDescending で降順で並べ替えます。 
Header xlNo (既定値) でヘッダなし、xlGuess でヘッダがあるかどうかチェック、xlYes でヘッダありとして並べ替えます。
OrderCustom ユーザー定義の並べ替えリスト内の番号を示す1から始まる整数です。省略すると、通常の並べ替えが使用されます。
MatchCase Trueの場合、大文字と小文字を区別して、Falseの場合、大文字と小文字を区別しないで並べ替えを行います。
Orientation xlSortRows (既定値) で行単位の並べ替え、xlSortColumns で列単位の並べ替えを行います。
SortMethod xlPinYin (既定値)で中国語の発音表記の順、xlStroke で各文字の総画数の順に並べ替えます。 
DataOption xlSortNormal (既定値) で数値とテキストを別々に、xlSortTextAsNumbers でテキストを数値データとして並べ替えます。 

Header、Order、OrderCustom、Orientation の設定は、並べ替え機能を使用するまたは、Sortメソッドを利用するごとに、エクセル内部にパラメータが保存されます。これらの引数を省略した場合、前回保存されている値が使用されるため注意が必要です。
Sortメソッドで確実な並べ替えを行うためには、これらの引数を明示的に設定する必要があります。
※ 要素数の上限値に注意してください。Excel2003までは65536行、Excel2007は1048576行を超える並べ替えはエラーになります。
※ シートを利用する上で"1-2"や"01/01"などのデータは日付として、"-"や"="で始まる文字列は数式として扱われます。注意してください。

Quickソート(クイックソート)による並べ替え
(例)
Public Sub test()
Dim i As Long
Dim MyLng() As Long
Dim LngMin As Long
Dim LngMax As Long
Const CstLng As Long = 10
  ReDim MyLng(1 To CstLng, 0)
  LngMin = LBound(MyLng)
  LngMax = UBound(MyLng)
  For i = 1 To UBound(MyLng)
     MyLng(i, 0) = Int(Rnd * UBound(MyLng))
  Next i
  Call DoQuickSort(MyLng, LngMin, LngMax)
End Sub

Public Sub DoQuickSort(ByRef pMyLng As Variant, ByVal pLngMin As Long, ByVal pLngMax As Long)
Dim i As Long
Dim j As Long
Dim Base As Long
Dim Buf As Long
  Base = pMyLng((pLngMin + pLngMax) \ 2, 0)
  i = pLngMin
  j = pLngMax
  Do
    Do While pMyLng(i, 0) < Base
      i = i + 1
    Loop
    Do While pMyLng(j, 0) > Base
      j = j - 1
    Loop
    If i >= j Then
      Exit Do
    Else
      Buf = pMyLng(i, 0)
      pMyLng(i, 0) = pMyLng(j, 0)
      pMyLng(j, 0) = Buf
      i = i + 1
      j = j - 1
    End If
  Loop
  If pLngMin < i - 1 Then
    Call DoQuickSort(pMyLng, pLngMin, i - 1)
  End If
  If pLngMax > j + 1 Then
    Call DoQuickSort(pMyLng, j + 1, pLngMax)
  End If
End Sub
この例では、配列MyLngに10個の要素の乱数を格納し、DoQuickSort関数で並べ替えを行います。引数を参照渡ししているのでDoQuickSortの処理が終わった時点で、配列MyLngの各要素も並べ替えが終了しています。

クイックソートは汎用的な並べ替え方法で他言語でもよく利用されます。DoQuickSort関数が本体のプロシージャです。この中で再帰的に呼び出しを行い並べ替えを行います。
※ 再起処理に関してはこちらでも解説しています。いろいろな繰り返し方法を知ろう!

クイックソートは非常に高速です。それはすなわち、クイックソートのアルゴリズムが非常によく考えられたソートアルゴリズムであるといえるでしょう。
クイックソートのアルゴリズムは簡単に説明すると、ベースになる基準値(配列の真ん中の要素)を定め、左から(配列の先頭から)さらに、右から(配列の後方から)基準値以下の値、また以上の値を調べ、見つかるごとに値を入れ替えていきます。これを繰り返し、さらに再起処理で要素の前半部分、後半部分と並べ替えを行わせ、最終的に正しい昇順(もしくは降順)に並べ替えるというものです。

本体の部分は次のような記述もできます。
Public Sub DoQuickSort(ByRef pMyLng As Variant, ByVal pLngMin As Long, ByVal pLngMax As Long)
Dim i As Long
Dim j As Long
Dim BaseNum As Long
Dim BaseVal As Long
Dim Buf As Long
  If pLngMin >= pLngMax Then
    Exit Sub
  Else
    BaseNum = (pLngMin + pLngMax) \ 2
    BaseVal = pMyLng(BaseNum, 0)
    pMyLng(BaseNum, 0) = pMyLng(pLngMin, 0)
    i = pLngMin
    For j = pLngMin + 1 To pLngMax
      If pMyLng(j, 0) < BaseVal Then
        i = i + 1
        Buf = pMyLng(i, 0)
        pMyLng(i, 0) = pMyLng(j, 0)
        pMyLng(j, 0) = Buf
      End If
    Next
    pMyLng(pLngMin, 0) = pMyLng(i, 0)
    pMyLng(i, 0) = BaseVal
    Call DoQuickSort(pMyLng, pLngMin, i - 1)
    Call DoQuickSort(pMyLng, i + 1, pLngMax)
  End If
End Sub
こちらでも、同じくクイックソートを行います。アルゴリズムが若干違いますが、考え方は同じです。

コードは記述しませんが、クイックソートのほかにも有名なソート法がいくつかあります。名前だけでも紹介しておきます。

バブルソート 最も古くからあるアルゴリズムで、隣り合う要素を比較、入替を繰り返して行う方法です。
挿入ソート バブルソートの発展型です。要素を入れ替えるのではなく正しい位置に挿入していく方法です。
選択ソート 挿入ソートとバブルソートの中間にあたり、要素の位置を交換することで正しい配置にします。
ヒープソート 予備ソートで親子ツリーを作成、次にツリーを使って全体をソートする2段階ソートです。
シェルソート ある間隔で要素を取り出した部分を整列、更に間隔をつめた部分を取り出し整列します。

ソートアルゴリズムに関してはこの他にも数多くの手法があり、とてもここでは解説しきれませんが、このようなものがあるということはぜひ知っておいてください。

ADOオブジェクトのSortプロパティによる並べ替え

ExcelVBAからでも、ADOレコードセットオブジェクトが利用できます。レコードセットオブジェクトのSortプロパティを用いることでも、簡単に並べ替えが可能です。
※ ADOレコードセットの詳しい解説は、こちらを参照してください。ADOレコードセットを操作しよう12
※ 参照設定で「Microsoft ActiveX Data ObjectX.X Library」にチェックを入れる必要があります。(X.Xはバージョン名)
(例)
Public Sub test()
Dim i As Long
Dim MyLng() As Long
Dim MyRngSet As Range
Dim SQL As String
Dim CN As ADODB.Connection
Dim RS As ADODB.Recordset
Const CstLng As Long = 10
  ReDim MyLng(1 To CstLng, 0)
  For i = 1 To UBound(MyLng)
    MyLng(i, 0) = Int(Rnd * UBound(MyLng))
  Next i
  Set MyRngSet = Range("A1:A" & UBound(MyLng))
    MyRngSet = MyLng
  Set CN = New ADODB.Connection
    CN.Provider = "Microsoft.Jet.OLEDB.4.0"
    CN.Properties("Extended Properties") = "Excel 8.0"
    CN.Open ThisWorkbook.FullName
  SQL = "SELECT * FROM [" & ActiveSheet.Name & "$]"
  Set RS = New ADODB.Recordset
    RS.CursorLocation = adUseClient
    RS.Open SQL, CN, adOpenStatic, adLockReadOnly
    RS.Sort = RS.Fields(0).Name
  For i = 1 To UBound(MyLng)
    MyLng(i, 0) = RS.Fields(0)
    RS.MoveNext
  Next i
End Sub
この例では、配列MyLngをアクティブシートのセル範囲A1:A10にセットした後、自ブックのアクティブシートにADO接続し、レコードセットを作成、RS.Sort = RS.Fields(0).Name で並べ替えたのち、配列MyLngに格納しなおしています。
CN.Open ThisWorkbook.FullName は自ブックへフルパスで接続を行っています。
SQL = "SELECT * FROM [" & ActiveSheet.Name & "$]" は現在アクティブなシートをSQL文字列に指定しています。RS.CursorLocation = adUseClient はSortプロパティを使用するためのCursorLocationプロパティの値として指定が必要です。

Sortプロパティの構文は次のようになります。
Recordsetオブジェクト.Sort = "フィールド名 並び順の指定"
  ・フィールド名 レコードセットのフィールド名(項目名)を指定します。
  ・並び順 ASC で昇順に、DESC で降順に並べ替えます。
(例)
  RS.Sort = "ID ASC,DATE DESC"
この例では、"ID"フィールドを昇順に、"DATE"フィールドを降順に並べ替えます。

サンプルコードでは1次元要素の並べ替えを行っているだけですが、複数のフィールドがあるシートならKey項目を複数指定できます。また、RangeオブジェクトのSortメソッドのように一度に3Keyまでというような制限はありません。

また次のようにすれば、シートにデータを転写しなくてもレコードセットオブジェクト単体で並べ替えを行うことも可能です。
(例)
Public Sub test()
Dim i As Long
Dim MyLng() As Long
Dim MyRngSet As Range
Dim RS As ADODB.Recordset
Const CstLng As Long = 10
  ReDim MyLng(1 To CstLng, 0)
  For i = 1 To UBound(MyLng)
     MyLng(i, 0) = Int(Rnd * UBound(MyLng))
  Next i
  Set RS = New ADODB.Recordset
    RS.Fields.Append "TMP", adInteger
    RS.CursorLocation = adUseClient
    RS.Open
  For i = 1 To UBound(MyLng)
    RS.AddNew
    RS.Fields(0) = MyLng(i, 0)
    RS.Update
  Next i
  RS.Sort = RS.Fields(0).Name
  For i = 1 To UBound(MyLng)
    MyLng(i, 0) = RS.Fields(0)
    RS.MoveNext
  Next i
End Sub
この例では、レコードセットを作成したら、RS.Fields.Append "TMP", adInteger の部分で"TMP"というフィールドを追加しています。その後、Forループで配列MyLngの中身をレコードセットに転記、RS.Sort = RS.Fields(0).Name の部分で並べ替えた後、再び配列MyLngに格納しなおしています。

この例も、追加するフィールドを増やすことで複数のフィールドをもつ2次元配列を複数のKey項目で並べ替えることが可能です。



最後に、参考までに各ソート法ごとの処理時間を計測してみます。(1万個の乱数値による並べ替え)

ソート方法(単位ミリ秒) 計測1回目 計測2回目 計測3回目
RangeオブジェクトのSortメソッド 110 110 94
クイックソート(上サンプル) 47 62 62
クイックソート(下サンプル) 62 63 79
ADOオブジェクト(上サンプル) 907 906 954
ADOオブジェクト(下サンプル) 266 265 266

こうしてみると、クイックソートのスピードには目を見張るものがあります。また、エクセル本来のSortメソッドもシートへの読み書きというハンデを負ってなおこのスピードは特筆すべきです。

以上、さまざまなソート(並べ替え)について解説しました。
どの並べ替えが優れているというのではなく、どの方法もケースバイケースで利用できたほうが様々な開発シーンで役立つと思います。
ぜひ、参考にしてください。

>> 次の話にすすむ


サイト内検索ができます

Microsoft Most Valuable Professional

Microsoft MVP Excel
武藤 玄 プロフィール
 

■■■ 執筆した書籍 ■■■
 

EXCEL VBA 業務自動化
 

Excel VBA を5日でマスターする本
 

仕事を速くする Excel VBA 入門
 

Excel VBAと業務改善のポイントがわかる本
 

Access VBA ベーシック スタンダード
 

Excel VBA アクションゲーム作成入門
 

■■■ 連載中の記事 ■■■
 

Excel VBAで業務改善!
 

実務で使うExcel VBA
 


TOPページ


■ エクセルVBA超入門

 ・9ステップで"Hello World!"
  からオブジェクト指向まで!
  1."Hello World!"を表示しよう
  2.基本はデータの入出力
  3.繰り返し処理
  4.シートで簡易データベース
  5.名前をつけよう
  6.構造化プログラムに挑戦
  7.構造体を使ってみよう
  8.フォームを使ってみよう
  9.オブジェクト指向に挑戦

■ エクセルVBA中級編

 ・VBAでいろんなテクニック
  変数・関数のスコープ
  引数の参照方法を明示
  配列の中身を一気に複写
  識別子がよいコードを作る
  データ定義型をもっと知ろう
  定数と列挙型を活用しよう
  エラー処理の重要性1
  エラー処理の重要性2
  いろいろな条件分岐
  いろいろな繰り返し処理
  演算子について知ろう
  文字列操作 連結 変換 置換
  文字列操作 検索 比較 書式
  日付操作関数を知ろう
  数値操作・評価・その他関数
  並び替えソートをマスター
  いろいろな検索をマスター
  VBEditorを使いこなそう
  マクロの記録を活用しよう1
  マクロの記録を活用しよう2
  VBAからVBEを操作しよう1
  VBAからVBEを操作しよう2
  VBAからVBEを操作しよう3
 ・ワークシートを使いこなす
  セルの参照をマスターしよう
  セルの選択をマスターしよう
  セルの操作をマスターしよう
  セルの書式設定をマスターしよう
  行・列の操作をマスターしよう
  シートの参照をマスターしよう
  シートの操作をマスターしよう
  ブックの操作をマスターしよう
  ウィンドウの操作をマスターしよう
  イベントプロシージャを活用しよう
  ワークシートを印刷しよう1
  ワークシートを印刷しよう2
  音声(読み上げ)機能を操作しよう
  グラフを操作しよう
 ・ユーザーフォームを使いこなす
  ユーザーフォームを使おう
  UserFormsオブジェクト
  Labelコントロール
  TextBoxコントロール
  ComboBoxコントロール
  ListBoxコントロール
  CheckBoxコントロール
  OptionButtonコントロール
  ToggleButtonコントロール
  CommandButtonコントロール
  ScrollBarコントロール
  SpinButtonコントロール
 ・VBA関数の一覧
  Aから始まる関数の一覧
  Cから始まる関数の一覧
  Dから始まる関数の一覧
  Eから始まる関数の一覧
  Fから始まる関数の一覧
  Gから始まる関数の一覧
 
■ エクセルVBAを極める
 VBAスーパーテクニック
 
 ・データベースへ接続してみよう!
  CSVファイルへの接続
  ワークシートへの接続
  mdbファイルへの接続
  SQL Serverへの接続
  ADOレコードセットの操作1
  ADOレコードセットの操作2
 ・ファイルを操作してみよう!
  FileSystemObjectの操作
  Drive File Folderの操作
  TextStream ダイアログ
  ステートメントでファイル操作1
  ステートメントでファイル操作2
 ・他アプリと連携してみよう!
  ActiveXオートメーションの操作
 ・ゲーム技でマクロを超える
  エクセルで音を鳴らす1
  エクセルで音を鳴らす2  
  スクリーン座標を取得
  様々なイベント取得
  リボンUIを制御しよう1
  リボンUIを制御しよう2
  シート上でアニメを動かそう
 
■ 一歩上行くエクセル
 基本操作の完全マスター!

 
 ・あなたはいったい
  エクセルで何をしたいのか?
  エクセルで業務効率化
  エクセル関数を使いこなす
  エクセルの便利技
  エクセルは最高の帳票ツール
 ・エクセル基本操作上級編!
  セル選択、コメント、シリアル値
  オート機能を使いこなそう!
  参照、条件付書式、入力規則
  関数をもっと理解しよう!
  配列数式を有効利用しよう!
  データの正規化をしよう!
  ショートカットキーを利用しよう1
  ショートカットキーを利用しよう2
  Office用アプリを作成しよう!
  PowerPivotとExcelで簡単BI!
 ・世間の誤ったエクセルの
  べからず集
  エクセルで文章を書くべからず
  エクセルで図形を描くべからず
  エクセルでシステムをつくるな
 
■ エクセル関連その他

 ・エクセルコミニュティにあなたも
  参加しませんか?
  Excel関連リンク・コミニュティ
 ・VBの理解がVBAをマスターする
  最短距離!
  VB関連の老舗・大家サイト
 ・エクセルExcel大事典掲示板
 ・プライバシーポリシー

2000アイテムを超えるラベルを販売
送料無料、即納対応の優良ショップ
今買っているラベルより確実に安い!
OAラベルの販売専科グラフトラベル




エクセルExcel大事典ははリンクフリーです エクセル大事典Excel大事典
お問い合わせはこちら gengengen@yahoo.co.jp

Copyright© Gen Muto 武藤 玄 All Rights Reserved,