I want to sort TObjectList<T>
using my own comparer function the comparer function code shown below.
I want from my ObjectList to be able to sort in two direction ascending and descending in order to accomplish this I use SysUtil.CompareText which has two parameters S1 and S2 and to sort in descending way I just opposite the sign of the CompareText result. I don't know if exist another solution everything is fine if s1 greater than S2 or vice versa however if s1 = s2 in the normal case there is no reindex in the list because all elements in the column are identical but the Opposite happened TObjectList sorted the list as if s1 > s2 or s1 < s2..
My question is how implement a comparer that supports equality and differences?
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;
if s1 = s2 in the normal case there is no reindex in the list because all elements in the column are identical
That is wrong idea. Computer should do what you told it - but nothing more. If you told computer that those objects are equal (in other word, comparator function returned zero) - then the computer is in his right to put them in ANY ORDER that suits his internal sorting implementation.
If you do want some SPECIFIC order among clusters of objects with the same ID - that just means that objects with same ID are NOT REALLY EQUAL, at least not all of those.
Sure, if IDs differ - then objects do as well. But even if those IDs are the same - as long as you care about ordering, that just proves that those objects are still DIFFERENT to You and ID equality is just NOT ENOUGH to specify objects totally equal. And that means You should use nesting, cascading comparator, using more and more finegrain tests until difference spotted.
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;
Comparing is a kind of mathematics, kind of Algebra. You prove some axioms and then some theories start to work. But only after axioms proving and not more than actual theorem terms.
The very fact that you care about order of objects with the same ID shows that the axiom is false. The comparison is more complex process than ID alone. You have to make a comparator that would only return zero on truly equal o\bjects, in other words the objects about which respective order you don't care absolutely.
Try reading http://www.howzatt.demon.co.uk/articles/2011-05-equality.html