Delphi 字符串排序
Delphi String Sort
我有一个非常大的文件,如下所示
45313904626416486480179546360796323469287116537171
465573254230695450538671922463236910370073247307526
5906233480284069039032926795367974774430427486375
这种num如何排序?
结果应该是这样的(真实文件是 100000 行):
5906233480284069039032926795367974774430427486375
45313904626416486480179546360796323469287116537171
465573254230695450538671922463236910370073247307526
我尝试使用
MyFlexibleArray := TList<UInt64>.Create;
AssignFile(F, OpenTextFileDialog1.FileName);
Reset(F);
repeat
Readln(F, str);
MyFlexibleArray.Add(UInt64(str));
until EOF(F);
CloseFile(F);
MyFlexibleArray.Sort;
对于 TStringList,结果不是以自然方式排序!
任何帮助将不胜感激。
首先,您的文本文件已损坏。包含NUL字节,无法正常解析
但是,如果我们忽略这个问题,像这样对文件进行排序几乎是微不足道的。
假设没有前导零,以下算法将给出正确的结果:
var Data := TFile.ReadAllLines('K:\numbers.txt', TEncoding.ASCII);
TArray.Sort<string>(
Data,
TComparer<string>.Construct(
function(const L, R: string): Integer
begin
Result := CompareValue(L.Length, R.Length);
if Result <> 0 then
Exit;
for var i := 1 to L.Length do
begin
Result := CompareValue(Ord(L[i]), Ord(R[i]));
if Result <> 0 then
Exit;
end;
end
)
);
TFile.WriteAllLines('K:\sorted.txt', Data, TEncoding.ASCII);
我们根据这些规则构造我们自己的字符串比较器:
- 如果
L
比R
的位数多(少),那么显然它更大(更小)。
- 如果
L
和R
的位数相同,则从MSD到LSD逐一比较。
只需将 IOUtils
、Generics.Defaults
、Generics.Collections
和 Math
添加到您的 uses
子句中。
您可以将大数字保留在 TStringList 中的字符串中,并使用自定义比较器对其进行排序,该比较器首先按字符串长度排序,然后(如果长度相等)按字符串值排序。像这样:
function NumberStringComparer(List: TStringList; Index1, Index2: Integer): Integer;
var
Value1, Value2: string;
Len1, Len2: Integer;
begin
Value1 := List[Index1];
Value2 := List[Index2];
Len1 := Length(Value1);
Len2 := Length(Value2);
Result := Len1 - Len2;
if Result = 0 then
begin
if Value1 = Value2 then
Result := 0
else if Value1 > Value2 then
Result := 1
else
Result := -1;
end;
end;
用法示例:
MyStringList.CustomSort(NumberStringComparer);
如果您将数据排序为字符串,则不会考虑字符串的长度。
如果您使用 Generic
(因此您的 uses
子句中需要 System.Generics.Collections
),您可以指定如何将参数中的对象与构造函数进行比较。这意味着您的字符串列表将声明为:
FMyStrings: TList<String>;
你的比较器会比较两个字符串,如果你假设字符串只能包含十进制数字那么你的比较器会是这样的:
TMyStringSorter = class(TComparer<String>)
public
function Compare(const Left, Right: String): Integer; override;
end;
function TMyStringSorter.Compare(const Left, Right: String): Integer;
begin
if(Length(Left)<Length(Right) then Result:=-1
else if(Length(Right)<Length(Left) then Result:=1
else Result:=CompareStr(Left, Right);
end;
然后把Interface传给比较器给TList构造函数,就可以按照自己的排序算法排序了。
我有一个非常大的文件,如下所示
45313904626416486480179546360796323469287116537171
465573254230695450538671922463236910370073247307526
5906233480284069039032926795367974774430427486375
这种num如何排序?
结果应该是这样的(真实文件是 100000 行):
5906233480284069039032926795367974774430427486375
45313904626416486480179546360796323469287116537171
465573254230695450538671922463236910370073247307526
我尝试使用
MyFlexibleArray := TList<UInt64>.Create;
AssignFile(F, OpenTextFileDialog1.FileName);
Reset(F);
repeat
Readln(F, str);
MyFlexibleArray.Add(UInt64(str));
until EOF(F);
CloseFile(F);
MyFlexibleArray.Sort;
对于 TStringList,结果不是以自然方式排序!
任何帮助将不胜感激。
首先,您的文本文件已损坏。包含NUL字节,无法正常解析
但是,如果我们忽略这个问题,像这样对文件进行排序几乎是微不足道的。
假设没有前导零,以下算法将给出正确的结果:
var Data := TFile.ReadAllLines('K:\numbers.txt', TEncoding.ASCII);
TArray.Sort<string>(
Data,
TComparer<string>.Construct(
function(const L, R: string): Integer
begin
Result := CompareValue(L.Length, R.Length);
if Result <> 0 then
Exit;
for var i := 1 to L.Length do
begin
Result := CompareValue(Ord(L[i]), Ord(R[i]));
if Result <> 0 then
Exit;
end;
end
)
);
TFile.WriteAllLines('K:\sorted.txt', Data, TEncoding.ASCII);
我们根据这些规则构造我们自己的字符串比较器:
- 如果
L
比R
的位数多(少),那么显然它更大(更小)。 - 如果
L
和R
的位数相同,则从MSD到LSD逐一比较。
只需将 IOUtils
、Generics.Defaults
、Generics.Collections
和 Math
添加到您的 uses
子句中。
您可以将大数字保留在 TStringList 中的字符串中,并使用自定义比较器对其进行排序,该比较器首先按字符串长度排序,然后(如果长度相等)按字符串值排序。像这样:
function NumberStringComparer(List: TStringList; Index1, Index2: Integer): Integer;
var
Value1, Value2: string;
Len1, Len2: Integer;
begin
Value1 := List[Index1];
Value2 := List[Index2];
Len1 := Length(Value1);
Len2 := Length(Value2);
Result := Len1 - Len2;
if Result = 0 then
begin
if Value1 = Value2 then
Result := 0
else if Value1 > Value2 then
Result := 1
else
Result := -1;
end;
end;
用法示例:
MyStringList.CustomSort(NumberStringComparer);
如果您将数据排序为字符串,则不会考虑字符串的长度。
如果您使用 Generic
(因此您的 uses
子句中需要 System.Generics.Collections
),您可以指定如何将参数中的对象与构造函数进行比较。这意味着您的字符串列表将声明为:
FMyStrings: TList<String>;
你的比较器会比较两个字符串,如果你假设字符串只能包含十进制数字那么你的比较器会是这样的:
TMyStringSorter = class(TComparer<String>)
public
function Compare(const Left, Right: String): Integer; override;
end;
function TMyStringSorter.Compare(const Left, Right: String): Integer;
begin
if(Length(Left)<Length(Right) then Result:=-1
else if(Length(Right)<Length(Left) then Result:=1
else Result:=CompareStr(Left, Right);
end;
然后把Interface传给比较器给TList构造函数,就可以按照自己的排序算法排序了。