さて、最終回になる予定の第3回です。
ソートといっても、降順ソート、数値ソート、大/小文字区別ソート等いろいろと考えられます。
これらを実装しようという話です。
type
TCompare = function(const S1, S2: string): Integer;
function StrCompAsNum(const Str1, Str2: string): Integer;
var
Num1, Num2: Extended;
begin
if not TextToFloat(PChar(Str1), Num1, fvExtended) then Num1 := 0.0;
if not TextToFloat(PChar(Str2), Num2, fvExtended) then Num2 := 0.0;
if Num1 = Num2 then Result := 0
else if Num1 < Num2 then Result := -1
else Result := 1;
end;
function StrCompAsNumRev(const Str1, Str2: string): Integer;
begin
Result := -StrCompAsNum(Str1, Str2);
end;
function CompareStrRev(const Str1, Str2: string): Integer;
begin
Result := -CompareStr(Str1, Str2);
end;
procedure TForm1.Sort(ACol: Integer);
procedure MergeSort(Buffer: TStringList; ARow, Count: Integer; Compare: TCompare);
var
I, J: Integer;
Center: Integer;
Temp: TStringList;
begin
if Count = 1 then Exit;
Center := Count div 2;
MergeSort(Buffer, ARow, Center, Compare);
MergeSort(Buffer, ARow + Center, Count - Center, Compare);
I := 0;
J := 0;
Temp := TStringList.Create;
while (I < Center) and (J < Count - Center) do
begin
if Compare(Buffer[ARow + I], Buffer[ARow + Center + J]) > 0 then
begin
Temp.AddObject(Buffer[ARow + Center + J], Buffer.Objects[ARow + Center + J]);
Inc(J);
end
else
begin
Temp.AddObject(Buffer[ARow + I], Buffer.Objects[ARow + I]);
Inc(I);
end;
end;
if I = Center then
while J < Count - Center do
begin
Temp.AddObject(Buffer[ARow + Center + J], Buffer.Objects[ARow + Center + J]);
Inc(J);
end
else
while I < Center do
begin
Temp.AddObject(Buffer[ARow + I], Buffer.Objects[ARow + I]);
Inc(I);
end;
for I := 0 to Count - 1 do
begin
Buffer[ARow + I] := Temp[I];
Buffer.Objects[ARow + I] := Temp.Objects[I];
end;
Temp.Free;
end;
var
S: string;
ARow: Integer;
Buffer: TStringList;
Compare: TCompare;
begin
with StringGrid1 do
begin
Buffer := TStringList.Create;
//Buffer に key とそれに対応する Rows を格納する
for ARow := TopRow to RowCount - 1 do
begin
if CaseSensitive then S := Cells[ACol, ARow]
else AnsiLowerCase(Cells[ACol, ARow]);
Buffer.AddObject(S, TStringList.Create);
TStringList(Buffer.Objects[ARow - TopRow]).Assign(Rows[ARow]);
end;
if Reverse then
begin
if Numerical then Compare := StrCompAsNumRev else Compare := CompareStrRev;
end
else
begin
if Numerical then Compare := StrCompAsNum else Compare := CompareStr;
end;
//Buffer を実際にソートする
MergeSort(Buffer, 0, RowCount - TopRow, Compare); //Buffer.Sort; と置き換え
//ソートしたデータを Grid に書き戻す
for ARow := TopRow to RowCount - 1 do
begin
Rows[ARow].Assign(TStringList(Buffer.Objects[ARow - TopRow]));
TStringList(Buffer.Objects[ARow - TopRow]).Free;
end;
Buffer.Free;
end;
end;
まあ、そう難しいことをやってるわけじゃないのでソースを比較すれば分かるでしょう。
CaseSensitive が大/小文字を区別するか、Numerical が数値ソートをするか、Reverse が降順ソートをするかということです。
しかし・・・結構長いソースだな。
あ、関数ってポインタで引き渡せるんですよ(笑)
知らなかった人、そういうものなんです(苦笑)