カスタムソートをクラス内だけで行うには?

解決


たかみちえ  URL  2003-07-22 08:45:07  No: 4177

ファイルリストを二つの条件でソートするなどの場合、
TStringList.CustomSortメソッドを使うことになりますけど、
このとき使うTStringListSortCompare型関数は、クラス内におくことはできないんでしょうか?
  クラスのメンバとして関数を宣言し、使おうとすると、
"型に互換性がありません:通常の手続きとメソッドポインタ"とコンパイルエラーになってコンパイルできません。
  クラス外に置くと、一応使うことはできますが、
それだと、Index1とIndex2以外のデータを、TStringListSortCompare関数内で使いたいときに、
そのデータの置き場がありません。
(クラス内に置くと、アクセスできないし、クラス外に置くと、クラスを二つ以上同時に生成させられなくなるし…)

  どうにかTStringList.CustomSortを、クラス内で終わらせるか、またはその代替えとなる方法はないでしょうか?
それとも、自前でクイックソートをしたほうが早いでしょうか?

  どうも基本がわかってないような気がしますけど、
わかる方どうかお願いします。


にしの  2003-07-22 17:29:09  No: 4178

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.

自前で作った方が、(処理速度的にも)早いと思いますよ。


たかみちえ  URL  2003-07-23 03:54:03  No: 4179

> 自前で作った方が、(処理速度的にも)早いと思いますよ。  
  そうですね…。たしかに、今回扱おうとしているのはTStringsだったので、TStringListに移す時間だけでも、自作すればかなり浮くかもしれませんね。

  ところで、ではソート関数を自作するということで、もう一つ質問が。
  CustomSortでは、0未満か0かそれより大きいを返し、その数値によってソートを行うようですけど、
実際に自分で実装する場合、
昇順の場合は、比較関数の結果が0未満ときはExchangeで入れ替え、さもなくばそのまま。
  降順の場合は、それに-1(符号を返せばいいのなら、最上位ビットを反転するだけでもいいかもしれませんが…)をかけた後に同じ判断。
  ということでいいんでしょうか?


にしの  2003-07-23 06:28:56  No: 4180

基本的にはそうですね。
クイックソートの場合、結果が不安定なことに注意です。
安定したソートが必要な場合は、マージソートですが、配列をマージする時間を考えると、(アルゴリズム的には実行時間 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は、不安定です。


たかみちえ  URL  2003-07-23 16:39:07  No: 4181

そうなんですか…。クイックソートもやはり欠点があるんですね。

  にしのさん本当にありがとうございました。とても勉強になりました。
以上を参考に、やってみようと思います。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加