【问题标题】:Sorting TObjectList<T> issue within same-comparator-value clusters在相同比较值集群中对 TObjectList<T> 问题进行排序
【发布时间】:2013-02-12 09:06:40
【问题描述】:

我想使用我自己的比较器函数对TObjectList&lt;T&gt;进行排序,比较器函数代码如下所示。

我希望我的 ObjectList 能够在升序和降序两个方向上进行排序以实现此目的我使用具有两个参数 S1 和 S2 的 SysUtil.CompareText 并以降序方式排序我正好与 CompareText 的符号相反结果。我不知道是否存在另一种解决方案,如果 s1 大于 S2,则一切都很好,反之亦然,但是如果 s1 = s2 在正常情况下,列表中没有重新索引,因为列中的所有元素都是相同的,但相反 发生 TObjectList 对列表进行排序,好像 s1 > s2 或 s1

我的问题是如何实现支持相等和差异的比较器?

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;

【问题讨论】:

  • 顺便说一句,您确定“字符串”是 Direction 参数的最佳选择吗?
  • 不,不是代码只是为了说明......
  • 您的比较函数正确报告列表中的所有项目都是相等的。当它们都相等时,为什么它们的顺序很重要?也许你需要研究的主题是稳定排序
  • 我无法理解这个问题。你有什么问题?
  • 如果 tobjectlist 对 id 字段进行排序,我不只有 id 字段,而且不应该使 name 字段也排序 Arioch '比我更好的解释感谢所有成员......跨度>

标签: delphi generics sorting tobjectlist


【解决方案1】:

如果 s1 = s2 在正常情况下,列表中没有重新索引,因为列中的所有元素都是相同的

这是错误的想法。计算机应该按照您说的去做——但仅此而已。 如果您告诉计算机这些对象是相等的(换句话说,比较器函数返回零) - 那么计算机有权将它们放在适合其内部排序实现的任何顺序中。

如果您确实希望在具有相同 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

【讨论】:

  • @David - 如果我需要的话,我会的。但实际上,只要用 代替 作为排序主题,就可以在需要时将任何算法更改为稳定。
  • @David,也是话题发起者,想要使用标准的 Comparator 接口和一些库存容器。我认为在这种情况下,假设所使用的排序算法及其实现细节是不安全的。稍后你会从一些 3rd 方库或不同的 Delphi 版本中获取容器,并且排序算法属性可能会改变。
猜你喜欢
  • 2011-06-14
  • 2022-01-20
  • 1970-01-01
  • 2013-04-24
  • 2014-01-21
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多