排序 TObjectList<T> 交换相等的值
Posted
技术标签:
【中文标题】排序 TObjectList<T> 交换相等的值【英文标题】:Sorting TObjectList<T> swaps equal values [duplicate] 【发布时间】: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 实现是一个稳定的排序。这是我们添加它的主要原因。 【参考方案1】:这是设计使然。内部使用的快速排序实现不是一个稳定的实现,因此需要重新排序相等的项目。为了使排序稳定,您需要扩展比较器以考虑到这一点。 F.I.当 DoubleValue 属性相等时,您可以比较 Text 属性。
【讨论】:
当今软件的一个常见问题:只能对一列进行排序,而不是能够链接多列。如果前一列的比较结果相等,我通常对每一列使用Array of Byte
来排序每个字节代表另一列索引的位置。
@AmigoJack 您始终可以让您的 Comparer 函数接受两个对象/记录,而不仅仅是来自这些对象的单个参数,然后在您的 Comaprer 方法中以尽可能多的杠杆和所需的任何顺序比较单个参数.
@SilverWarior 我这样做。我说的还有很多其他人没有。
那个解决方案是贴膏药。到目前为止,更好的方法是使用稳定的排序以上是关于排序 TObjectList<T> 交换相等的值的主要内容,如果未能解决你的问题,请参考以下文章