我有一个名称/值对的TStringList。这些名称都是9个整数值,当然是字符串),值都是字符串(以逗号分隔)。
e.g。
5016=Catch the Fish!,honeyman,0
30686=Ozarktree1 Goes to town,ozarktreel,0
。 。
我想调用add例程并在TStringlist中添加新行,但之后需要一种方法对列表进行排序。
e.g。
Tags.Add(frmTag.edtTagNo.Text + '=' +
frmTag.edtTitle.Text + ',' +
frmTag.edtCreator.Text + ',' +
IntToStr(ord(frmTag.cbxOwned.Checked)));
Tags.Sort;
以下是我的尝试:
Tags:= TStringList.Create;
Tags.CustomSort(StringListSortComparefn);
Tags.Sorted:= True;
我的自定义排序例程:
function StringListSortComparefn(List: TStringList; Index1, Index2: Integer): Integer;
var
i1, i2 : Integer;
begin
i1 := StrToIntDef(List.Names[Index1], 0);
i2 := StrToIntDef(List.Names[Index2], 0);
Result:= CompareValue(i1, i2);
end;
但是,它似乎仍然像字符串而不是整数一样对它们进行排序。
我甚至尝试创建自己的类:
type
TXStringList = class(TStringList)
procedure Sort;override;
end;
implementation
function StringListSortComparefn(List: TStringList; Index1, Index2: Integer): Integer;
var
i1, i2 : Integer;
begin
i1 := StrToIntDef(List.Names[Index1], 0);
i2 := StrToIntDef(List.Names[Index2], 0);
Result:= CompareValue(i1, i2);
end;
procedure TXStringList.Sort;
begin
CustomSort(StringListSortComparefn);
end;
我甚至在SO上尝试过一些例子(例如Sorting TSTringList Names property as integers instead of strings)
有人能告诉我我做错了什么吗?每次,列表都按字符串排序,而不是整数。
30686=Ozarktree1 Goes to town,ozarktreel,0
5016=Catch the Fish!,honeyman,0
答案 0 :(得分:6)
你可以做一个简单的整数减法:
function StringListSortComparefn(List: TStringList; Index1, Index2: Integer): Integer;
var
i1, i2 : Integer;
begin
i1 := StrToIntDef(List.Names[Index1], 0);
i2 := StrToIntDef(List.Names[Index2], 0);
Result := i1 - i2
end;
要反转排序顺序,只需在减法中反转操作数:
Result := i2 - i1;
这是一个快速,可编辑的控制台示例:
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes;
function StringListSortProc(List: TStringList; Index1, Index2: Integer): Integer;
var
i1, i2: Integer;
begin
i1 := StrToIntDef(List.Names[Index1], -1);
i2 := StrToIntDef(List.Names[Index2], -1);
Result := i1 - i2;
end;
var
SL: TStringList;
s: string;
begin
SL := TStringList.Create;
SL.Add('3456=Line 1');
SL.Add('345=Line 2');
SL.Add('123=Line 3');
SL.Add('59231=Line 4');
SL.Add('545=Line 5');
WriteLn('Before sort');
for s in SL do
WriteLn(#32#32 + s);
SL.CustomSort(StringListSortProc);
WriteLn('');
WriteLn('After sort');
for s in SL do
WriteLn(#32#32 + s);
ReadLn;
SL.Free;
end.
结果输出:
Before sort
3456=Line 1
345=Line 2
123=Line 3
59231=Line 4
545=Line 5
After sort
123=Line 3
345=Line 2
545=Line 5
3456=Line 1
59231=Line 4
答案 1 :(得分:3)
问题是,您是否要求列表保持排序?或者在添加完所有项目后,最后对它进行排序就足够了。
如果您只是需要能够根据需要对列表进行排序,那么您的第一个示例几乎是正确的。添加完项目后,您最后需要在最后调用CustomSort。
Tags := tStringList . Create;
Tags . Add ( '5016=Catch the Fish!,honeyman,0' );
Tags . Add ( '30686=Ozarktree1 Goes to town,ozarktreel,0' );
Tags.CustomSort(StringListSortComparefn);
如果您需要列表保持排序,则需要覆盖CompareStrings。
type
TXStringList = class(TStringList)
function CompareStrings(const S1, S2: string): Integer; override;
end;
function NumberOfNameValue ( const S : string ) : integer;
begin
Result := StrToIntDef(copy(S,1,pos('=',S)-1), 0);
end;
function txStringList . CompareStrings ( const S1, S2 : string ) : integer;
var
i1, i2 : Integer;
begin
i1 := NumberOfNameValue ( S1 );
i2 := NumberOfNameValue ( S2 );
Result:= CompareValue(i1, i2);
end;
begin
Tags := txstringlist . Create;
Tags . Sorted := true;
Tags . Add ( '5016=Catch the Fish!,honeyman,0' );
Tags . Add ( '30686=Ozarktree1 Goes to town,ozarktreel,0' );
// List will be correctly sorted at this point.
end;
答案 2 :(得分:3)
CustomSort
命令是一次性操作。您似乎正在使用它,就像您正在设置属性一样,以便进一步排序将使用自定义比较功能,但这并不是它的工作原理。它对(新创建的,空的)列表进行一次排序。然后,当您设置Sorted
属性时,使用默认比较和 重新排序列表,您指定列表的任何进一步添加应该是使用该默认排序顺序插入。
当您覆盖Sort
方法时,您更接近解决方案,但插入排序列表(其中Sorted=True
)实际上并未调用Sort
!相反,他们执行二进制搜索正确的插入位置,然后插入。您可以尝试覆盖Sort
:
CompareStrings
type
TXStringList = class(TStringList)
protected
function CompareStrings(const S1, S2: string): Integer; override;
end;
function TXStringList.CompareStrings(const S1, S2: string): Integer;
var
i1, i2, e1, e2: Integer;
begin
Val(S1, i1, e1);
Assert((e1 = 0) or (S1[e1] = NameValueSeparator));
Val(S2, i2, e2);
Assert((e2 = 0) or (S2[e2] = NameValueSeparator));
Result := CompareValue(i1, i2);
end;
请注意,这会破坏IndexOf
方法。它也可能会中断Find
,但您可能想要,具体取决于您希望如何使用相同的数字键处理元素。 (Find
是用于定位排序列表的正确插入点的内容,并且使用上面的代码,它将使用相同的键处理所有元素。)它们都使用{{1}就像CompareStrings
一样。