ソートとは、数字を何らかの規則に従って並べることをいいます。今回は、単純に数値を小さい順に並べて見ましょう。並べる方法は、いくつかあります。ここでは、直接選択法というのをやってみたいと思います。
やり方は簡単で、とりあえずソートしたい数値を一つの配列として最初に格納しておきます。まだ、何もしていませんので、数値の並び方はバラバラのままです。 とりあえす最初の数値から番号をつけていきます。最初の数値を0番として、以下1番、2番、3番・・・と、しておきます。 最初に0番の数値を一番小さいと仮定しておきます。もちろん実際には、その後に並んでいる数字に小さいのがあるかもしれませんので、あくまで仮定です。 まずはじめに、0番以降の数値の中から一番小さい数を見つけて、それを0番の数値と交換します。(もちろん、もし0番の数値が一番小さかったら、交換はしません)これで、0番には確実に一番小さいのが入りました。 ここで、とりあえず0番のことはもう考えません。0番はほっときます。 次に1番以降のことを考えます。 また、さっきやったことと同じように今度は1番を一番小さい数と仮定します。そして、2番以降の中で一番小さかった数を1番と交換します。(もちろん2番目以降の数で見つかった数より1番の数のほうが小さかったら交換はしません)これで1番が一番小さい数になりました。(0番のことは、考えてませんので注意してください。)ここで、0番の時と同じように1番のことも考えません。ほって置きます。今度は、2番以降についてやって行きます。また、2番目を一番小さい数と仮定して、3番目以降から一番小さい数を・・・・。と繰り返して行きます。最終的には、全体を通して、小さい順に並んでいるというわけです。
では、さっそくプログラムを書いてみましょう。 今回は、Editに入力した数値をソートして、ラベルに表示するというようにしたいと思います。 まず、フォームにラベルとEditを5個ずつ貼り付けて下さい。こんな感じになります。
プログラムはこんな感じになりました。
procedure TForm1.Button1Click(Sender: TObject); var i, j, min, soeji, temp: Integer; Arr: array[0..4] of Integer; begin Arr[0] := StrToInt(Edit1.Text); Arr[1] := StrToInt(Edit2.Text); Arr[2] := StrToInt(Edit3.Text); Arr[3] := StrToInt(Edit4.Text); Arr[4] := StrToInt(Edit5.Text); for i := 0 to 4 do begin min := Arr[i]; // とりあえず一番最初の値を最小とする soeji := i; for j := i + 1 to 4 do begin if (Arr[j] < min) then // 小さいのが見つかれば、交換 begin min := Arr[j]; soeji := j; end; end; temp := Arr[i]; // 交換します Arr[i] := Arr[soeji]; Arr[soeji] := temp; end; Label1.Caption := IntToStr(Arr[0]); Label2.Caption := IntToStr(Arr[1]); Label3.Caption := IntToStr(Arr[2]); Label4.Caption := IntToStr(Arr[3]); Label5.Caption := IntToStr(Arr[4]); ShowMessage('ソート完了しました'); end;
二つの値を交換するときに、ここでは、まず一時変数tempに一方の数値を代入して、そしてもう片方の数値をtempに代入した方の変数に代入して、最後にtempから値をもらって交換を成立させています。文章でみると、ややこしくなりますがプログラムで見た場合、分かりやすいと思います。
上記のプログラムの場合、Edit に文字列が入力された場合には例外が生成されます。そこで型変換に失敗した時は、失敗したこと知らせるメッセージを表示して再度ユーザーに整数を入力させるようにして見ましょう。それには、文字列から整数に型変換する際に、StrToInt ではなく TryStrToInt を使ってやります。この TryStrToInt は、与えられた文字列が整数に変換できた場合には True が返され、整数に変換できない時は、False が返されるようになっています。これを用いて、上のプログラムを改良してみます。
新たに ListBox をフォームに貼り付けて下さい。
procedure TForm1.Button3Click(Sender: TObject); var i, j, min, soeji, temp: Integer; Arr: array[0..4] of Integer; begin // Edit に入力されたものが整数に変換できない場合には、 // TryStrToInt は False を返します。 // not が付いていますので、True は False になり、 // False は、True になります。 // つまり、not を付けると、真偽が逆になる事になります。 if (not TryStrToInt(Edit1.Text, Arr[0])) or (not TryStrToInt(Edit2.Text, Arr[1])) or (not TryStrToInt(Edit3.Text, Arr[2])) or (not TryStrToInt(Edit4.Text, Arr[3])) or (not TryStrToInt(Edit5.Text, Arr[4])) then begin ShowMessage('整数へ変換できませんでした。'); exit; // 手続きから抜け出します。 // つまり、これ以降に続くプログラムコードは実行されません。 end; for i := 0 to 4 do begin min := Arr[i]; soeji := i; for j := i+1 to 4 do begin if (Arr[j] < min) then begin min := Arr[j]; soeji := j; end; end; temp := Arr[i]; Arr[i] := Arr[soeji]; Arr[soeji] := temp; end; for i := 0 to 4 do ListBox1.Items.Add(IntToStr(Arr[i])); end;
TryStrToInt は2つのパラメータをとります。第1パラメータには、整数に変換したい文字列を、第2パラメータには、整数に変換された値が代入されます。
これで、整数に変換できない文字が入力された場合、そのメッセージを表示させる事が出来ました。再度「整数を入力してください」と、メッセージを表示してユーザに再び入力のやり直しをさせる事が出来ます。また、exit はコメントに書いてある様に手続きから抜け出す際に使用します。ループから抜け出す時は、break を用い、手続きから抜け出すには exit を使うと覚えておくと便利かもしれません。
ここでもう一度、TryStrToInt を使用している部分を見てみましょう。
if (not TryStrToInt(Edit1.Text, Arr[0])) or (not TryStrToInt(Edit2.Text, Arr[1])) or (not TryStrToInt(Edit3.Text, Arr[2])) or (not TryStrToInt(Edit4.Text, Arr[3])) or (not TryStrToInt(Edit5.Text, Arr[4])) then
どれも同じようなコードになっています。Edit の添え字と、配列 Arr の添え字が異なるだけで、後は同じです。for 文で何とか出来そうに見えます。ですが、コンポーネントである Edit の添え字を、for 文ではちょっと扱えないように見えます。
そんな時は、FindComponent を使ってやります。FindComponent で TEdit のName プロパティをパラメータとして渡してやると、その指定した Name プロパティを持つコンポーネントにアクセスする事が出来ます。具体的には、以下のようにして使います。また、ソートを実行している部分を別の関数にしました。
procedure MySort(var Arr: array of Integer); var i, j, min, soeji, temp: Integer; begin for i := Low(Arr) to High(Arr) do begin min := Arr[i]; soeji := i; for j := i+1 to 4 do begin if (Arr[j] < min) then begin min := Arr[j]; soeji := j; end; end; temp := Arr[i]; Arr[i] := Arr[soeji]; Arr[soeji] := temp; end; end; procedure TForm1.Button1Click(Sender: TObject); var NumArr: array[0..4] of Integer; EditText: string; i: Integer; begin for i := 0 to 4 do begin // TEdit コンポーネント(Edit1〜Edit5)の Text プロパティを // EditText に代入しています。 EditText := TEdit(FindComponent('Edit'+IntToStr(i+1))).Text; if not TryStrToInt(EditText, NumArr[i]) then begin ShowMessage('不正な文字がありました。'); exit; end; end; MySort(NumArr); // ソートします。 for i := 0 to 4 do ListBox1.Items.Add(IntToStr(NumArr[i])); end;
FindComponent に渡す引数は、Name プロパティですので注意してください。(※Name プロパティについては、「Caption と Name プロパティ」を参考にして下さい。)
今回の場合、Edit の Name プロパティが Edit1, Edit2..Edit5 となっており、Edit(x) のように x を添え字とし利用することができましたが、例えば Edit の Name プロパティに規則性がない場合には、どのようにしたら良いのでしょうか。
Edit の Name プロパティに規則性がない場合には、フォームに貼り付けてある TEdit コンポーネントを見つけてから、その TEdit の Text プロパティにアクセスしてやる方法があります。具体的には以下のようになります。
procedure MySort(var Arr: array of Integer); var i, j, min, soeji, temp: Integer; begin for i := Low(Arr) to High(Arr) do begin min := Arr[i]; soeji := i; for j := i+1 to 4 do begin if (Arr[j] < min) then begin min := Arr[j]; soeji := j; end; end; temp := Arr[i]; Arr[i] := Arr[soeji]; Arr[soeji] := temp; end; end; procedure TForm1.Button2Click(Sender: TObject); var NumArr: array[0..4] of Integer; i, index: Integer; begin index := 0; for i := 0 to ComponentCount-1 do begin if Components[i] is TEdit then // TEdit コンポーネントなら begin if not TryStrToInt(TEdit(Components[i]).Text, NumArr[index]) then begin ShowMessage('不正な文字がありました。'); exit; end; Inc(index); end; end; MySort(NumArr); // ソートします。 for i := 0 to 4 do ListBox1.Items.Add(IntToStr(NumArr[i])); end;
ComponentCount は、貼り付けてあるコンポーネントの総数を取得する事が出来ます。Components は、コンポーネントの配列になっています。ここでは、この配列には、TButton と TEdit が格納されている事になります。(Label がフォームに貼り付けてあるならラベルもこの配列に格納されています。)そして、貼り付けてあるコンポーネントを1つずつ TEdit かどうかを調べ、TEdit であるなら、その Text プロパティを取得し、その値を TryStrToInt に渡して整数に変換し、配列 NumArr にその変換された値を代入しています。(整数に変換できない場合は、その旨メッセージを表示し、exit で手続きを終了しています。)
なんとか Name プロパティに規則性がない場合でも、うまく切り抜けられました。ただ今回の場合、フォームに貼り付けてある Edit は整数を入力する為に存在する Edit だけしかありませんが、もし、それ以外の為に使用される Edit がフォームに貼り付けてあった場合は、不具合が発生することになります。ですから、上記の場合でもうまくいかないことになります。これをうまく切り抜けるには、一つの方法として Tag プロパティを使う方法があります。整数を入力する為に存在する Edit には Tag プロパティに適当な数値を代入して、それ以外の Edit とは差別化をはかり区別してやります。Tag プロパティの使用方法は、こちらを参考にして下さい。