delphi - 如何使用 TComparer 对记录列表进行排序?
问题描述
我有一条记录,其中包含有关文件的数据:
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
and b = -2147483640
as Integer
s; 很明显a > b
,但是减法会产生错误的结果。
相反,你应该总是做类似的事情
if a = b then
Result := 0
else if a < b then
Result := -1
else
Result := 1;
但是 Delphi 的 RTL 已经包含了这方面的功能:单元中有几个CompareValue
重载Math
(对于不同类型的整数和浮点数 - 但不幸的是,不是Cardinal
s)。
因此,尽管如果您这样做,您的代码段“大部分时间”都会起作用
Result := Integer(A.FileSize) - Integer(B.FileSize)
这还不够好:一方面,不是每个Cardinal
人都适合Integer
. 此外,如上所述,减法不是要走的路。
在你的情况下,你可以直接使用if
上面的东西,或者你可以为 s 创建一个新的CompareValue
重载Cardinal
。或者,你可以做
Result := CompareValue(Int64(A.FileSize), Int64(B.FileSize)).
(另外,正如其他人在评论中所说,您应该重新考虑首先使用 aCardinal
来存储文件大小是否明智。如果您将其升级为 anInt64
或者UInt64
您可以简单地编写
Result := CompareValue(A.FileSize, B.FileSize).)
推荐阅读
- ruby-on-rails - 尝试让 rails 在我的 Mac 上工作时遇到错误
- spring-boot - 版本 spring boot、spring cloud、ribbon 不工作
- sql - 用于检查新旧表值的 Oracle sql 触发器
- bash - Bash:如何检查文件的第一个字符是否为{
- kotlin - Android Kotlin Safe-Args 导航回 Fragment 而无需再次传递参数
- microsoft-graph-api - 无法从 OneNoteAPI 获取图像内容
- vue.js - 如何使用Vue.js将变量传递给同一级别的不同组件
- angular - TypeError:无法读取未定义的属性“canGoBack”
- python - 所有列的 2 列之间的相关性
- reactjs - 为什么我更新安全规则后无法将数据写入 Firebase