Reputation: 794
Looking into the example How to make an Excel-Like Sort By A, Then By B in a TObjectList<> using multiple comparers I have built the following test
program Project3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Generics.Defaults,
System.Generics.Collections,
System.Contnrs,
System.SysUtils;
type
TPerson = class(TObject)
age: Integer;
name: string;
public
constructor Create(aAge: Integer; aName: string); reintroduce;
end;
TSortCriterion<T> = class(TObject)
Ascending: Boolean;
Comparer: IComparer<T>;
end;
TSortCriteriaComparer<T> = class(TComparer<T>)
private
SortCriteria: TObjectList<TSortCriterion<T>>;
public
constructor Create;
destructor Destroy; override;
function Compare(const Right, Left: T): Integer; override;
procedure ClearCriteria; virtual;
procedure AddCriterion(NewCriterion: TSortCriterion<T>); virtual;
end;
TPersonAgeComparer = class(TComparer<TPerson>)
public
function Compare(const Left, Right: TPerson): Integer; override;
end;
TPersonLastNameComparer = class(TComparer<TPerson>)
public
function Compare(const Left, Right: TPerson): Integer; override;
end;
{ TSortCriteriaComparer<T> }
procedure TSortCriteriaComparer<T>.AddCriterion(NewCriterion: TSortCriterion<T>);
begin
SortCriteria.Add(NewCriterion);
end;
procedure TSortCriteriaComparer<T>.ClearCriteria;
begin
SortCriteria.Clear;
end;
function TSortCriteriaComparer<T>.Compare(const Right, Left: T): Integer;
var
Criterion: TSortCriterion<T>;
begin
for Criterion in SortCriteria do
begin
Result := Criterion.Comparer.Compare(Right, Left);
if not Criterion.Ascending then
Result := -Result;
if Result <> 0 then
Exit;
end;
end;
constructor TSortCriteriaComparer<T>.Create;
begin
inherited;
SortCriteria := TObjectList<TSortCriterion<T>>.Create(True);
end;
destructor TSortCriteriaComparer<T>.Destroy;
begin
SortCriteria.Free;
inherited;
end;
{ TPersonAgeComparer }
function TPersonAgeComparer.Compare(const Left, Right: TPerson): Integer;
begin
if Left.age > Right.age then
Result := -1
else if Left.age < Right.age then
result := 1
else
result := 0;
end;
{ TPersonLastNameComparer }
function TPersonLastNameComparer.Compare(const Left, Right: TPerson): Integer;
begin
if Left.name > Right.name then
Result := -1
else if Left.name < Right.name then
result := 1
else
result := 0;
end;
{ TPerson }
constructor TPerson.Create(aAge: Integer; aName: string);
begin
Age := aAge;
name := aName;
end;
var
PersonComparer: TSortCriteriaComparer<TPerson>;
Criterion: TSortCriterion<TPerson>;
PeopleList: TObjectList<TPerson>;
Person: TPerson;
begin
PersonComparer := TSortCriteriaComparer<TPerson>.Create;
try
Criterion := TSortCriterion<TPerson>.Create;
Criterion.Ascending := True;
Criterion.Comparer := TPersonAgeComparer.Create;
PersonComparer.AddCriterion(Criterion);
Criterion := TSortCriterion<TPerson>.Create;
Criterion.Ascending := True;
Criterion.Comparer := TPersonLastNameComparer.Create;
PersonComparer.AddCriterion(Criterion);
PeopleList := TObjectList<TPerson>.Create;
PeopleList.Sort(PersonComparer);
Person := TPerson.Create(26, 'Smith');
PeopleList.Add(Person);
Person := TPerson.Create(26, 'Jones');
PeopleList.Add(Person);
Person := TPerson.Create(24, 'Jones');
PeopleList.Add(Person);
Person := TPerson.Create(34, 'Lincoln');
PeopleList.Add(Person);
finally
PersonComparer.Free;
end;
end.
but instead of giving the following outcome
Lastname ▲ Age ▲
---------------------
Jones 24
Jones 26
Smith 26
Lincoln 34
I have this one
Lastname ▲ Age ▲
---------------------
Smith 26
Jones 26
Jones 24
Lincoln 34
I tried to change TPersonLastNameComparer.Comparer
and TPersonAgeComparer.Comparer
but I cannot get the desided outcome.
What am I doing wrong ?
Upvotes: 0
Views: 483
Reputation: 794
Thanks to the input from David I was able to fix this. Here the correct code:
program Project3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Generics.Defaults,
System.Generics.Collections,
System.Contnrs,
System.SysUtils;
type
TPerson = class(TObject)
age: Integer;
name: string;
public
constructor Create(aAge: Integer; aName: string); reintroduce;
end;
TSortCriterion<T> = class(TObject)
Ascending: Boolean;
Comparer: IComparer<T>;
end;
TSortCriteriaComparer<T> = class(TComparer<T>)
private
SortCriteria: TObjectList<TSortCriterion<T>>;
public
constructor Create;
destructor Destroy; override;
function Compare(const Right, Left: T): Integer; override;
procedure ClearCriteria; virtual;
procedure AddCriterion(NewCriterion: TSortCriterion<T>); virtual;
end;
TPersonAgeComparer = class(TComparer<TPerson>)
public
function Compare(const Left, Right: TPerson): Integer; override;
end;
TPersonLastNameComparer = class(TComparer<TPerson>)
public
function Compare(const Left, Right: TPerson): Integer; override;
end;
{ TSortCriteriaComparer<T> }
procedure TSortCriteriaComparer<T>.AddCriterion(NewCriterion: TSortCriterion<T>);
begin
SortCriteria.Add(NewCriterion);
end;
procedure TSortCriteriaComparer<T>.ClearCriteria;
begin
SortCriteria.Clear;
end;
function TSortCriteriaComparer<T>.Compare(const Right, Left: T): Integer;
var
Criterion: TSortCriterion<T>;
begin
for Criterion in SortCriteria do
begin
Result := Criterion.Comparer.Compare(Right, Left);
if not Criterion.Ascending then
Result := -Result;
if Result <> 0 then
Exit;
end;
end;
constructor TSortCriteriaComparer<T>.Create;
begin
inherited;
SortCriteria := TObjectList<TSortCriterion<T>>.Create(True);
end;
destructor TSortCriteriaComparer<T>.Destroy;
begin
SortCriteria.Free;
inherited;
end;
{ TPersonAgeComparer }
function TPersonAgeComparer.Compare(const Left, Right: TPerson): Integer;
begin
if Left.age > Right.age then
Result := 1
else if Left.age < Right.age then
result := -1
else
result := 0;
end;
{ TPersonLastNameComparer }
function TPersonLastNameComparer.Compare(const Left, Right: TPerson): Integer;
begin
if Left.name > Right.name then
Result := 1
else if Left.name < Right.name then
result := -1
else
result := 0;
end;
{ TPerson }
constructor TPerson.Create(aAge: Integer; aName: string);
begin
Age := aAge;
name := aName;
end;
var
PersonComparer: TSortCriteriaComparer<TPerson>;
Criterion: TSortCriterion<TPerson>;
PeopleList: TObjectList<TPerson>;
Person: TPerson;
begin
PersonComparer := TSortCriteriaComparer<TPerson>.Create;
try
Criterion := TSortCriterion<TPerson>.Create;
Criterion.Ascending := True;
Criterion.Comparer := TPersonAgeComparer.Create;
PersonComparer.AddCriterion(Criterion);
Criterion := TSortCriterion<TPerson>.Create;
Criterion.Ascending := True;
Criterion.Comparer := TPersonLastNameComparer.Create;
PersonComparer.AddCriterion(Criterion);
PeopleList := TObjectList<TPerson>.Create;
Person := TPerson.Create(26, 'Smith');
PeopleList.Add(Person);
Person := TPerson.Create(26, 'Jones');
PeopleList.Add(Person);
Person := TPerson.Create(24, 'Jones');
PeopleList.Add(Person);
Person := TPerson.Create(34, 'Lincoln');
PeopleList.Add(Person);
PeopleList.Sort(PersonComparer);
finally
PersonComparer.Free;
TradeList.Free;
end;
end.
Upvotes: 1