2

我有以下(简化的)类定义:

  TMyObject = class
  private
    FDoubleValue: Double;
    FText: string;
  protected
  public
    constructor Create(ADoubleValue: Double; AText: string);
    property DoubleValue: Double read FDoubleValue write FDoubleValue;
    property Text: string read FText write FText;
  end;

以下示例代码显示了我如何对TObjectList<TMyObject>( FMyObjects) 进行排序并将它们显示在TListBox.

constructor TfrmMain.Create(AOwner: TComponent);
begin
  inherited;
  FMyObjects := TObjectList<TMyObject>.Create;
  FMyObjects.OwnsObjects := true; // Default but for clarity
end;

destructor TfrmMain.Destroy;
begin
  FMyObjects.Free;
  inherited;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
var
  ii: Integer;
begin
  FMyObjects.Add(TMyObject.Create(100.00, 'Item 1'));
  FMyObjects.Add(TMyObject.Create(200.00, 'Item 2'));
  FMyObjects.Add(TMyObject.Create(300.00, 'Item 3')); // Duplicate sort value
  FMyObjects.Add(TMyObject.Create(300.00, 'Item 4')); // Duplicate sort value
  FMyObjects.Add(TMyObject.Create(400.00, 'Item 5'));
  ObjectsToListBox;
end;

procedure TfrmMain.SortList;
var
  Comparer: IComparer<TMyObject>;
begin
  Comparer := TDelegatedComparer<TMyObject>.Create(
    function(const MyObject1, MyObject2: TMyObject): Integer
    begin
      result := CompareValue(MyObject1.DoubleValue, MyObject2.DoubleValue, 0);
    end);
  FMyObjects.Sort(Comparer);
end;

procedure TfrmMain.ObjectsToListBox;
var
  ii: Integer;
begin
  ListBox1.Items.Clear;
  for ii := 0 to FMyObjects.Count - 1 do
    ListBox1.Items.Add(Format('%d - %.1f - %s', [ii, FMyObjects[ii].DoubleValue, 
       FMyObjects[ii].Text]));
end;

procedure TfrmMain.Button1Click(Sender: TObject);
begin
  SortList;
  ObjectsToListBox;
end;

每次Button1被点击(并且列表排序),FMyObjects[2](Item3)和FMyObjects[3]('Item4')在列表中交换位置。在我的“现实世界”(绘图)应用程序中,这是不可取的。

我还在CompareValue函数调用中尝试了 Epsilon 的不同值以及匿名函数的不同实现(比较值并返回 1、-1 或 0),但似乎两者都没有区别。

我是否遗漏了某些东西(例如控制此行为的属性)或者这是“设计使然”并且无法防止?

4

1 回答 1

2

这是设计使然。内部使用的快速排序实现不是一个稳定的实现,因此需要重新排序相等的项目。为了使排序稳定,您需要扩展比较器以将其考虑在内。当DoubleValue属性相等时,您可以比较Text属性。

于 2021-12-18T11:27:49.487 回答