簡體   English   中英

自定義將Delphi TStringList名稱/值對排序為整數

[英]Custom Sort a Delphi TStringList name/value pairs as integers

我有一個名稱/值對的TStringList。 這些名稱都是9個整數值,當然是字符串),值都是字符串(以逗號分隔)。

例如

5016=Catch the Fish!,honeyman,0
30686=Ozarktree1 Goes to town,ozarktreel,0

我想調用add例程並在TStringlist中添加新行,但之后需要一種方法對列表進行排序。

例如

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上嘗試了一些例子(例如,將TSTringList Names屬性排序為整數而不是字符串

有人能告訴我我做錯了什么嗎? 每次,列表都按字符串排序,而不是整數。

30686=Ozarktree1 Goes to town,ozarktreel,0
5016=Catch the Fish!,honeyman,0

你可以做一個簡單的整數減法:

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

問題是,您是否要求列表保持排序? 或者在添加完所有項目后,最后對它進行排序就足夠了。

如果您只需要能夠根據需要對列表進行排序,那么您的第一個示例幾乎是正確的。 添加完項目后,您最后需要在最后調用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;

CustomSort命令是一次性操作。 您似乎正在使用它,就好像您正在設置屬性,以便進一步排序將使用自定義比較功能,但這不是它的工作原理。 它對(新創建的,空的)列表進行一次排序。 然后,當您設置Sorted屬性時,使用默認比較重新排序列表, 指定應使用該默認排序順序插入列表的任何進一步添加。

當您重寫Sort方法時,您更接近解決方案,但插入到排序列表( Sorted=True )實際上並不調用Sort 相反,他們執行二進制搜索正確的插入位置,然后插入。 您可以嘗試重寫CompareStrings ,而不是重寫Sort

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是用於定位排序列表的正確插入點的內容,並且使用上面的代碼,它將使用相同的鍵處理所有元素。)它們都像Sort一樣使用CompareStrings

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM