0

TObjectList<T>以下に示す比較関数コードを独自の比較関数を使用して並べ替えたいと思います。

これを達成するために、ObjectList から昇順と降順の 2 方向に並べ替えることができるようにしたいのですが、これを行うには、S1 と S2 の 2 つのパラメーターを持つ SysUtil.CompareText を使用します。別の解決策が存在するかどうかはわかりません。s1がS2より大きい場合、またはその逆の場合はすべて問題ありませんが、通常の場合、s1 = s2の場合、列のすべての要素は同一ですが、反対が発生したため、リストに再インデックスはありません TObjectList sortedあたかも s1 > s2 または s1 < s2..

私の質問は、等値と差をサポートする比較子をどのように実装するかです。

TPerson = class
private
  FName: string;
  FId: string;
public
  property Name: string read FName write FName;
  property ID: string read FID write FID;
end;

TPersons = class(TObjectList<TPerson>)
public
  constructor Create();
  procedure Sort(Direction: string); reintroduce;
end;

procedure TForm4.Button1Click(Sender: TObject);
var
  PersonsList: TPersons;
  I: Integer;
begin
  PersonsList := TPersons.Create;
  PersonsList.Sort('Ascending');
  for I := 0 to PersonsList.Count - 1 do
    ShowMessage(PersonsList[i].Name);
end;

{ TPersons }

constructor TPersons.Create;
var
  Person: TPerson;
begin
  Person := TPerson.Create;
  Person.Name := 'fateh';
  Person.ID := '1';
  Self.Add(Person);

  Person := TPerson.Create;
  Person.Name := 'mohamed';
  Person.ID := '1';
  Self.Add(Person);

  Person := TPerson.Create;
  Person.Name := 'oussama';
  Person.ID := '1';
  Self.Add(Person);
  // all ids are identical
end;

procedure TPersons.Sort(Direction: string);
var
  Comparer   : IComparer<TPerson>;
  Comparison : TComparison<TPerson>;
begin
  if Direction = 'Ascending' then

    Comparison := function(const Person1, Person2 : TPerson): Integer
                  begin
                    result := CompareText(Person1.ID, Person2.ID);
                  end;

  if Direction = 'Descending' then

    Comparison := function(const Person1, Person2 : TPerson): Integer
                  begin
                    result := - CompareText(Person1.ID, Person2.ID);
                  end;

    Comparer := TComparer<TPerson>.Construct(Comparison);

    inherited Sort(Comparer);
end;
4

1 に答える 1

3

通常のケースで s1 = s2 の場合、列内のすべての要素が同一であるため、リストに再インデックスはありません

それは間違った考えです。コンピュータはあなたが言ったことを実行するはずですが、それ以上のことは何もしません。これらのオブジェクトが等しい (つまり、比較関数が 0 を返した) ことをコンピューターに伝えた場合、コンピューターは、内部の並べ替えの実装に適した任意の順序でそれらを配置する権利があります。

同じIDを持つオブジェクトのクラスター間で特定の順序が必要な場合は、同じIDを持つオブジェクトが実際には等しくないことを意味します。少なくともそれらのすべてではありません。

もちろん、ID が異なる場合は、オブジェクトも同様です。しかし、それらの ID が同じであっても、順序を気にする限り、それはそれらのオブジェクトがまだあなたにとって異なっていることを証明するだけであり、ID の同等性は、オブジェクトを完全に同等に指定するのに十分ではありません。つまり、違いが見つかるまで、ネスト、カスケード コンパレータを使用し、より細かいテストを使用する必要があります。

Comparison := function(const Person1, Person2 : TPerson): Integer
  begin
     Result := CompareText(Person1.ID, Person2.ID);
     if Result <> 0 then exit;

     Result := CompareText(Person1.Name, Person2.Name);
     if Result <> 0 then exit;

     Result := Person1.Age - Person2.Age;
     if Result <> 0 then exit;

     Result := GenderCompare(Person1.Sex, Person2.Sex);
     if Result <> 0 then exit;

     Result := Person1.Salary - Person2.Salary;
     if Result <> 0 then exit;

     ...et cetera
  end;

比較は一種の数学、一種の代数です。いくつかの公理を証明すると、いくつかの理論が機能し始めます。しかし、公理が証明された後でのみ、実際の定理の項以上ではありません。

同じ ID を持つオブジェクトの順序を気にするというまさにその事実は、公理が間違っていることを示しています。比較は、ID のみよりも複雑なプロセスです。真に等しいオブジェクト、つまり、それぞれの順序について絶対に気にしないオブジェクトに対してのみゼロを返すコンパレータを作成する必要があります。

http://www.howzatt.demon.co.uk/articles/2011-05-equality.htmlを読んでみてください

于 2013-02-26T21:00:20.243 に答える