ファイルリストを二つの条件でソートするなどの場合、
TStringList.CustomSortメソッドを使うことになりますけど、
このとき使うTStringListSortCompare型関数は、クラス内におくことはできないんでしょうか?
クラスのメンバとして関数を宣言し、使おうとすると、
"型に互換性がありません:通常の手続きとメソッドポインタ"とコンパイルエラーになってコンパイルできません。
クラス外に置くと、一応使うことはできますが、
それだと、Index1とIndex2以外のデータを、TStringListSortCompare関数内で使いたいときに、
そのデータの置き場がありません。
(クラス内に置くと、アクセスできないし、クラス外に置くと、クラスを二つ以上同時に生成させられなくなるし…)
どうにかTStringList.CustomSortを、クラス内で終わらせるか、またはその代替えとなる方法はないでしょうか?
それとも、自前でクイックソートをしたほうが早いでしょうか?
どうも基本がわかってないような気がしますけど、
わかる方どうかお願いします。
TListViewなどのソートとは違うみたいですね。TListViewならば、LParamを渡せるのですが。
StringListのソートですが、1ユニット1関数にすればできます。
単純な例ですが、細かいところは修正してください。
# こんな大がかりでなくてもできそうですが・・・
unit uStringsSort;
interface
uses
classes;
type
TStringsSort=class;
TSortCompare=procedure(
Sender: TStringsSort;
List: TStringList;
Index1, Index2: Integer; var Compare: Integer) of object;
TStringsSort=class
private
FOnCompare: TSortCompare;
public
property OnCompare: TSortCompare read FOnCompare write FOnCompare;
end;
function Sort(List: TStringList; Index1, Index2: Integer): Integer;
var
StringsSort: TStringsSort;
implementation
function Sort(List: TStringList; Index1, Index2: Integer): Integer;
begin
if List[Index1] < List[Index2] then
Result := -1
else if List[Index1] > List[Index2] then
Result := 1
else
Result := 0;
if Assigned(StringsSort.OnCompare) then
begin
StringsSort.OnCompare(StringsSort, List, Index1, Index2, Result);
end;
end;
initialization
StringsSort := TStringsSort.Create;
StringsSort.OnCompare := nil;
finalization
StringsSort.Free;
end.
自前で作った方が、(処理速度的にも)早いと思いますよ。
> 自前で作った方が、(処理速度的にも)早いと思いますよ。
そうですね…。たしかに、今回扱おうとしているのはTStringsだったので、TStringListに移す時間だけでも、自作すればかなり浮くかもしれませんね。
ところで、ではソート関数を自作するということで、もう一つ質問が。
CustomSortでは、0未満か0かそれより大きいを返し、その数値によってソートを行うようですけど、
実際に自分で実装する場合、
昇順の場合は、比較関数の結果が0未満ときはExchangeで入れ替え、さもなくばそのまま。
降順の場合は、それに-1(符号を返せばいいのなら、最上位ビットを反転するだけでもいいかもしれませんが…)をかけた後に同じ判断。
ということでいいんでしょうか?
基本的にはそうですね。
クイックソートの場合、結果が不安定なことに注意です。
安定したソートが必要な場合は、マージソートですが、配列をマージする時間を考えると、(アルゴリズム的には実行時間 O(n log n)ですが)遅くなりそうです。
以下、余談です。
安定している場合では、大文字小文字の区別無しで'a', 'A'をソートした場合、
Strings[0] := 'a';
Strings[1] := 'A';
になります。
不安定な場合は、
Strings[0] := 'a';
Strings[1] := 'A';
もしくは
Strings[0] := 'A';
Strings[1] := 'a';
となります。
TStringListのCustomSortは、不安定です。
そうなんですか…。クイックソートもやはり欠点があるんですね。
にしのさん本当にありがとうございました。とても勉強になりました。
以上を参考に、やってみようと思います。
ツイート | ![]() |