【发布时间】:2020-06-08 20:41:42
【问题描述】:
我有一个包含文件数据的记录:
TYPE
RFile= record
public
FileName : string;
Resolution : Integer;
FileSize : Cardinal;
Rating : Byte;
end;
PFile= ^RFile;
我将这些文件/记录的列表保存在一个 TList
TFileList= class(TList<PFile>)
procedure SortByFilename;
procedure SortByRating;
procedure SortByResolution;
procedure SortBySize;
end;
我有诸如 SortByFilename、SortBySize 等方法来对列表进行排序。
我做“经典”排序。
现在我想升级到全新酷炫的 System.Generics.Defaults.TComparer。
据我了解,我需要为我的 TFileList 分配一个比较器,例如
TIntStringComparer = class(TComparer<String>)
public
function Compare(const Left, Right: String): Integer; override;
end;
我该怎么做?
如何为每个数据字段(文件名、文件大小、分辨率)处理一个比较器?
更新:
这段代码可以编译,但我有一个 EIntegerOverflow,因为 FileSize 是一个基数,而我返回一个整数(两个基数之间的差异)。
Sort(TComparer<PFile>.Construct(
function(CONST A,B: PFile): integer
begin
Result:= A.FileSize - B.FileSize;
end
));
【问题讨论】:
-
当你写一个数字类型的比较器时,你不应该使用减法,即使你的数据类型是有符号的(尝试将
a = 100和b = -2147483640比较为Integers;显然@987654328 @,但减法会产生错误的值)。相反,您应该始终比较:if a = b then Result := 0 else if a < b then Result := -1 else Result := 1。但是 Delphi 的 RTL 已经包含了这方面的功能:CompareValuefromMath。因此,尽管如果您使用Result := Integer(A.FileSize) - Integer(B.FileSize),您的 sn-p 将“大部分时间”工作,但它仍然不理想。 -
我看到
CompareValue对于Cardinal(32 位无符号)没有过载。但例如,您可以使用Result := CompareValue(Int64(A.FileSize), Int64(B.FileSize))。或者自己写if的东西。 -
为什么要存储指向记录的指针?
-
请注意,如果要处理大文件 (>4GB),文件大小应为
Int64。 -
@AndreasRejbrand - 谢谢。如果您发表评论作为答案,我会接受。