gpt4 book ai didi

delphi - 如何使用多个比较器在 TObjectList<> 中进行类似于 Excel 的按 A 排序,然后按 B 排序

转载 作者:行者123 更新时间:2023-12-03 14:34:47 29 4
gpt4 key购买 nike

我刚刚开始使用泛型,目前在对多个字段进行排序时遇到问题。

案例:
我有一个 PeopleList 作为 TObjectList<TPerson>我希望能够通过一次选择一个排序字段,但尽可能保留以前的排序来制作类似 Excel 的排序功能。

编辑:必须可以在运行时更改字段排序顺序。 (即,在一种情况下,用户想要排序顺序 A、B、C - 在另一种情况下,他想要 B、A、C - 在另一个 A、C、D 中)

假设我们有一个未排序的人员列表:

Lastname     Age
---------------------
Smith 26
Jones 26
Jones 24
Lincoln 34

现在如果我按姓氏排序:

Lastname ▲   Age
---------------------
Jones 26
Jones 24
Lincoln 34
Smith 26

然后,如果我按年龄排序,我想要这个:

Lastname ▲   Age ▲
---------------------
Jones 24
Jones 26
Smith 26
Lincoln 34

为了做到这一点,我制作了两个比较器 - 一个 TLastNameComparer 和一个 TAgeComparer。

我现在打电话

PeopleList.Sort(LastNameComparer)
PeopleList.Sort(AgeComparer)

现在我的问题是这不会产生我想要的输出,但是

Lastname ?   Age ?
---------------------
Jones 24
Smith 26
Jones 26
Lincoln 34

其中 Smith,26 出现在 Jones,26 之前。所以看起来它没有保留之前的排序。

我知道我可以只创建一个比较器来比较 LastName 和 Age - 但问题是,然后我必须为 TPerson 中存在的每个字段组合创建比较器。

是否可以使用多个 TComparer 来完成我想要的操作,或者如何完成我想要的操作?

新年更新

仅供将来访问者引用,这(几乎)是我现在使用的代码。

首先我做了一个基类TSortCriterion<T>和一个 TSortCriteriaComparer<T>以便将来能够在多个类(class)中使用它们。我已将标准和列表更改为 TObjectTObjectList分别,因为我发现如果对象列表自动处理标准的销毁会更容易。

  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;

implementation

{ 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;

最后,为了使用排序标准:(这只是为了示例,因为创建排序顺序的逻辑实际上取决于应用程序):

Procedure TForm1.SortList;
Var
PersonComparer : TSortCriteriaComparer<TPerson>;
Criterion : TSortCriterion<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.Sort(PersonComparer);
// Do something with the ordered list of people.
Finally
PersonComparer.Free;
End;
End;

最佳答案

将排序标准放入列表中,其中包括排序方向和用于比较项目的函数。像这样的记录可能会有所帮助:

type
TSortCriterion<T> = record
Ascending: Boolean;
Comparer: IComparer<T>;
end;

当用户配置所需的顺序时,用该记录的实例填充列表。

var
SortCriteria: TList<TSortCriterion>;

Comparer 成员将引用您已经编写的用于根据姓名和年龄进行比较的函数。现在编写一个引用该列表的比较函数。像这样的事情:

function Compare(const A, B: TPerson): Integer;
var
Criterion: TSortCriterion<TPerson>;
begin
for Criterion in SortCriteria do begin
Result := Criterion.Comparer.Compare(A, B);
if not Criterion.Ascending then
Result := -Result;
if Result <> 0 then
Exit;
end;
end;

关于delphi - 如何使用多个比较器在 TObjectList<> 中进行类似于 Excel 的按 A 排序,然后按 B 排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8672792/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com