【发布时间】:2022-01-20 22:49:23
【问题描述】:
我有以下(简化的)类定义:
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),但似乎都没有什么不同。
我是否遗漏了某些东西(例如控制此行为的属性)或者这是“设计使然”并且无法避免?
【问题讨论】:
-
这是因为 Delphi 排序实现者不稳定。这对于许多应用程序来说都很好,而且是设计使然。这在之前已经讨论过很多次了。在此处搜索稳定排序。 spring4d 中的 TimSort 实现是一个稳定的排序。这是我们添加它的主要原因。
标签: sorting delphi tobjectlist