delphi – 如何使一个类似Excel的A排序,然后通过B在TObjectList <>中使用多个比较器

前端之家收集整理的这篇文章主要介绍了delphi – 如何使一个类似Excel的A排序,然后通过B在TObjectList <>中使用多个比较器前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我刚刚开始使用泛型,我目前在多个字段上进行排序时遇到问题。

案件:
我有一个PeopleList作为一个TObjectList,我想通过一次选择一个排序字段,但是尽可能多地保留以前的排序,我想要做一个类似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

史密斯26号出现在琼斯之前,26岁。所以看起来它不保留以前的排序。

我知道我可以做一个比较LastName和Age的比较器,但是问题是,我必须对TPerson中存在的各个字段的每个组合进行比较。

有可能做我想要使用多个TComparers,或者我可以如何完成我想要的?

谢谢…

新年更新

祝你新年快乐。

只是为了参考未来的访客,这是(几乎)我现在使用的代码

首先,我做了一个基类TSortCriterion和一个TSortCriteriaComparer,以便将来可以在多个类中使用这些。
我将Criterion和列表分别更改为TObject和TObjectList,因为如果objectlist自动处理Criterion的销毁,我发现它更容易。

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相关文章