連載:VB 6ユーザーのための
これならマスターできるVB 2005超入門

第6回 配列ってこんなに便利だったの!?

羽山 博
2007/02/03
Page1 Page2 Page3

■コードの記述 〜 並べ替えの実行(SortとReverseを使って)

 まず、SortメソッドとReverseメソッドを使う方法から。これはいちばん単純な方法で、学習のコストやコーディングの手間はほとんどゼロ。保守性もいい。ただし、拡張性には欠ける。処理速度についてはやってみないと分からない。ともあれ、コードを見てみよう。

Private Sub sortArray1()
  t1 = Now
  Array.Sort(fKey, iData) ' fKeyをキーとして並べ替え
  Array.Reverse(fKey) ' 逆順にする
  Array.Reverse(iData) ' 逆順にする
  t2 = Now
  lblTicks.Text = (t2.Ticks - t1.Ticks).ToString
End Sub
昇順に並べ替えた後、逆順にするコード
  現在の時刻を取得する。
  配列を昇順に並べ替える。
  配列を逆順にする。
  配列を逆順にする。
  現在の時刻を取得する。
  かかった時間を求めて表示する。

 これは極めて単純。キー配列まで逆順にする必要はないのだが、ほかの方法と比較するために両方を逆順にしてある。

■コードの記述 〜 並べ替えの実行(IComparerインターフェイスを使って)

 では、次にIComparerインターフェイスを使う方法。インターフェイスというのは「クラスと同じようにプロパティやメソッド、イベントの定義はされているが、クラスと異なり、実装(実際にどういう動きをするか)は決められていないもの」とでもいった感じのものである。

 従って、インターフェイスを利用するときには、Implementsステートメントを使って、プロパティやメソッド、イベントを実装したクラスを作る必要がある。

Public Class frmRandom
    :
  Private Sub sortArray2()
    Dim myCompare As New RevCompare
    t1 = Now
    ' fKeyキーをキーとしてmyCompareの順(=逆順)に並べ替え
    Array.Sort(fKey, iData, myCompare)
    t2 = Now
    lblTicks.Text = (t2.Ticks - t1.Ticks).ToString
  End Sub
    :
End Class

Public Class RevCompare
  Implements IComparer

  Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
    If CSng(x) < CSng(y) Then
      Return 1 ' x < yのときは1を返す
    ElseIf CSng(x) > CSng(y) Then
      Return -1 ' x > yのときは-1を返す
    Else
      Return 0 ' x = yのときは0を返す
    End If
  End Function
End Class
IComparerインターフェイスを使って降順に並べ替えるコード
  RevCompareクラスのオブジェクト「myCompare」を作成する。
  ArrayクラスのSortメソッドで並べ替えを実行。並べ替え順序としてmyCompareを使う。
  RevCompareクラスの定義。
  このクラスではIComparerインターフェイスを実装する。
  Compare関数の定義。これはIComparerのCompareメソッドを実装するもの。
  比較の結果を返す。昇順なら「x > y」のときに0より大きい値を返すようにするが、降順にするため「x < y」のときに1を返すようにした。

 IComparerインターフェイスのCompareメソッドには決められた方法はないが、メソッドにパラメータとして渡されるxとyの大小関係によって以下のような値を返すものと定義されている

(1) x < y の場合 → 0より小さい値
(2) x = y の場合 → 0
(3) x > y の場合 → 0より大きい値

 従って、降順にしたければ、これとは逆の値を返すようにすればよい。 以降でそのコードを記述している。

 それにしても、複雑だ。できるだけ、「日本語」で解きほぐしてみると、次のようになるだろう。

  1. のArrayクラスのSortメソッドでは並べ替えの順序が指定できる。そのとき、大小比較に使われるIComparerインターフェイスの実装を指定する必要がある。

  2. ではIComparerインターフェイスを実装したクラスの名前を「RevCompare」としておき(実装は後回しにするとして)、「myCompare」という名前で新しいオブジェクトを作成する。これが で指定されたものだ。

  3. さて、IComparerインターフェイスを実装しないといけないわけだが、クラス名はRevCompareにしようと で決めていたので、 では「Public Class RevCompare」と書く。

  4. このRevCompareというクラスはIComparerインターフェイスを実装するものなので、 ではImplements IComparerと入力する。

  5. この時点で、 の1行は自動的に入力される(よかった。この長いコードをタイプしなくても済む!)。つまり、Compareメソッドを実装すればよいというわけだ。

  6. のように、単純に、既定の大小関係とは逆の結果を返すようにすれば降順になるじゃないか。

 私自身、.NET Frameworkクラス・ライブラリのリファレンスを何度も読み返して、ようやくおぼろげながらに分かってきたというぐらいの複雑さだが、確かにこの方法だと、並べ替えの順序を自由にカスタマイズできる。が、学習のコストやコーディングの手間はかなりかかる。保守性や拡張性は非常にいい。速度は後のお楽しみとしよう。

 なお、このコードを記述すると、Form.vbファイル内に複数のクラス定義が記述されることになる。フォームのクラス定義がファイルの先頭にないとデザイナ・ウィンドウにフォームが表示されなくなるので、RevCompareクラスの定義はファイルの最後に入力するようにしよう。

■コードの記述 〜 並べ替えの実行(DataGridViewコントロールを使って)

 最後は、DataGridViewコントロールを使う方法。これは簡単だ。さっきまでの「苦行」がウソのよう。さっそくコードを見てみよう。

Private Sub sortArray3()
  dgvWork.Visible = False
  t1 = Now

  ' DataGridViewのSortメソッドを使って並べ替え
  dgvWork.Sort(dgvWork.Columns(0), _
    System.ComponentModel.ListSortDirection.Descending)
  t2 = Now
  lblTicks.Text = (t2.Ticks - t1.Ticks).ToString
  dgvWork.Visible = True
End Sub
DataGridViewコントロールを使って並べ替えるコード
  DataGridViewコントロールのSortメソッドを利用する。キーとなる列と、降順であることを指定する。IntelliSenseが働くので、2番目のパラメータはリストから選択するだけでいい。

 DataGridViewのSortメソッドには、最初のパラメータにキーとなる列を指定し、2番目のパラメータには並べ替えの方向を指定する。行は長いが、IntelliSenseによって表示されるリストから選択するだけでいいので、入力は簡単だ。学習のコストはさほどかからないし、コードも簡単。保守性もいいが、拡張性もそこそこよさそうだ。

■実行結果と処理時間

 実行例の画面は図6のような感じになる。


図6 プログラムの実行例
ラジオ・ボタンで並べ替えの方法を選択し、[並べ替え]ボタンをクリックすると、処理にかかった時間が右上に表示される。単位はTick(100ナノ秒)。

 DateTimeクラスのTicksプロパティは、日時を西暦1年1月1日0時0分0秒からの経過時間を100ナノ秒単位で表しているので、並べ替えにかかった時間は、開始時と終了時の差が200288なら約20ミリ秒となる。

 手元の環境(Pentium III 750MHz、メモリ256Mbytes)で3回実行してみて平均を取ってみると、以下のようになった。

並べ替えの方法 かかった時間
SortとReverseを使う 200,288(約20ミリ秒)
IComparerインターフェイスを使う 7,176,987(約700ミリ秒)
DataGridViewコントロールを使う 4,206,048(約400ミリ秒)
並べ替えにかかる時間の計測結果

 このプログラムではリアルタイム・タイマーを使っているわけではないので、100ミリ秒以下の単位はあまり当てにならないが、かなりの差があることが分かる。ちなみにCore 2 Duo、メモリ2Gbytesの環境でも傾向は同じだった。

 このことからも、オブジェクトの作成や利用にはかなりのオーバーヘッドがかかることが分かる。つまり、大量のデータを取り扱うときは繰り返しの回数が多少増えてもシンプルな方法が良さそうだ(べき乗のオーダーで繰り返しが増える場合は話が別だが)。

 とはいえ、保守性や拡張性などの要素を無視していいというわけでもない。もっとも、実際に1万件のデータをメモリ上に展開して処理することはそうそうないかもしれないし、数百件程度のデータであれば体感速度にほとんど差は感じられないだろうから、データ量がさほど多くない場合は、状況に合わせて、学習コストや保守性、拡張性に重きを置いた方がいいだろう。

 なお、DataGridViewコントロールを使う方法は簡単で分かりやすいのだが、データを準備するのにとんでもなく時間がかかる。上の結果は並べ替えにかかった時間だけを測ったものなので400ミリ秒程度の速さとなっているが、データが準備できるまでに40秒近くかかった。DataGridViewコントロールで大量のデータを扱うのも現実的でない場合があることに注意しよう。

結び − 時には基本を見直すのもいいことだ

 今回は、配列の新しい機能を確認することから始めて、ずいぶんとヘンな方向に話がそれてしまった。

 .NET Frameworkクラス・ライブラリの「クラス」だけでもVB 6プログラマーには拒絶反応を起こして卒倒してしまう人が、私も含めずいぶんと多いと思うが(でも、数回の連載でだいぶ免疫はついてきたでしょ)、インターフェイスなるものまで登場してしまった。どこかで、「手続き・関数脳」を「オブジェクト指向脳」に切り替える必要があるのだろう。便利な新機能だけでなく、基本の理解も深めていきたいので、近いうちに「クラス」を正面から取り上げてみたいと思う。End of Article


 INDEX
  連載:VB 6ユーザーのためのこれならマスターできるVB 2005超入門
  第6回 配列ってこんなに便利だったの!?
    1.サンプル・プログラム7 − ランダムな並べ替えのためのコード
    2.サンプル・プログラム8 − 降順に並べ替えるいくつかの方法
  3.並べ替えを行う3つの方法を実装
 
インデックス・ページヘ  「これならマスターできるVB 2005超入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH