2012-11-06 94 views
29

我是一個Delphi新手,我不知道如何調用記錄的TList的排序方法,以按升序整數值排序記錄。 我有類似下面的記錄:如何使用自定義比較器對通用列表進行排序?

type 
    TMyRecord = record 
    str1: string; 
    str2: string; 
    intVal: integer; 
    end; 

認識到這些記錄泛型列表:

TListMyRecord = TList<TMyRecord>; 

曾經試圖找到在幫助文件的代碼,例如,發現這一個:

MyList.Sort(@CompareNames); 

我不能使用,因爲它使用類。於是,我就寫我自己的比較函數有一點不同的參數:

function CompareIntVal(i1, i2: TMyRecord): Integer; 
begin 
    Result := i1.intVal - i2.intVal; 
end; 

但是編譯器總是拋出一個「沒有足夠的參數」 - 當我把它與open.Sort(CompareIntVal);,這似乎是明顯的錯誤;所以我試圖更貼近幫助文件:

function SortKB(Item1, Item2: Pointer): Integer; 
begin 
    Result:=PMyRecord(Item1)^.intVal - PMyRecord(Item2)^.intVal; 
end; 

與PMyRecord爲PMyRecord = ^TMyRecord;

我試圖調用一個函數,總是得到一些錯誤的方式不同......

回答

36

Sort超載你應該使用是這個:

procedure Sort(const AComparer: IComparer<TMyRecord>); 

現在,你可以通過調用TComparer<TMyRecord>.Construct創建IComparer<TMyRecord> 。就像這樣:

var 
    Comparison: TComparison<TMyRecord>; 
.... 
Comparison := 
    function(const Left, Right: TMyRecord): Integer 
    begin 
    Result := Left.intVal-Right.intVal; 
    end; 
List.Sort(TComparer<TMyRecord>.Construct(Comparison)); 

我已經寫了Comparison功能匿名方法,但你也可以使用一個普通的老式非面向對象的功能,或對象的方法。

比較函數的一個潛在問題是您可能遭受整數溢出。所以你可以使用默認的整數比較器。

Comparison := 
    function(const Left, Right: TMyRecord): Integer 
    begin 
    Result := TComparer<Integer>.Default.Compare(Left.intVal, Right.intVal); 
    end; 

這可能是昂貴的調用TComparer<Integer>.Default反覆,所以你可以在一個全局變量分開存放它:

var 
    IntegerComparer: IComparer<Integer>; 
.... 
initialization 
    IntegerComparer := TComparer<Integer>.Default; 

另一種選擇要考慮的是在比較器來傳遞,當你創建列表。如果你只使用這個順序對列表進行排序,那更方便。

List := TList<TMyRecord>.Create(TComparer<TMyRecord>.Construct(Comparison)); 

然後你就可以對列表進行排序與​​

List.Sort; 
+0

謝謝檸了! 我需要包括任何東西'使用'除'使用''使用'除了'使用 Generics.Collections,...',因爲我得到'Tcomparison'和'IComparer''var'的未申報'var 比較:TComparison ; IntegerComparer:IComparer ;'? –

+0

您還需要Generics.Defaults。你有沒有找到RTL源代碼呢?這會幫助你。 –

+1

@David,你確定'TComparer'是你提供的代碼的不錯選擇嗎? 'TComparer'是爲了抽象基類。我建議使用'TDelegatedComparer'作爲你的代碼。 – TLama

2

我發現了一個更簡單的修改排序函數按字母順序排列的記錄或項目的非標準列表從TList。

PList = ^TContact; 
    TContact = record    //Record for database of user contact records 
     firstname1 : string[20]; 
     lastname1 : string[20]; 
     phonemobile : Integer;  //Fields in the database for contact info 
     phonehome : Integer; 
     street1 : string; 
     street2 : string; 

type 
    TListSortCompare = function (Item1, 
           Item2: TContact): Integer; 
var 
    Form1: TForm1; 
    Contact : PList;   //declare record database for contacts 
    arecord : TContact; 
    Contacts : TList; //List for the Array of Contacts 

function CompareNames(i1, i2: TContact): Integer; 
begin 
    Result := CompareText(i1.lastname1, i2.lastname1) ; 
end; 

,並呼籲排序列表中的功能

Contacts.Sort(@CompareNames); 
+1

您可能想要清理一下您的代碼示例。刪除未使用的變量。添加使用示例。糾正語法。 – Kromster

+4

最初的問題是關於對通用列表進行排序,而此示例使用的是標準TList(指針列表),這是不同的場景。 – ByteArts

0

,我想分享我的解決方案(基於我在這裏收集的輸入)。

這是一個標準設置。一個用於保存通用TObjectList中單個文件數據的filedata類。該列表具有兩個私有屬性fCurrentSortedColumn和fCurrentSortAscending來控制排序順序。 AsString方法是合併的路徑和文件名。

function TFileList.SortByColumn(aColumn: TSortByColums): boolean; 
var 
    Comparison: TComparison<TFileData>; 
begin 
    result := false; 
    Comparison := nil; 

    case aColumn of 
    sbcUnsorted : ; 
    sbcPathAndName: begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    sbcSize  : begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<int64>.Default.Compare(Left.Size,Right.Size); 
             if Result = 0 then 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    sbcDate  : begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<TDateTime>.Default.Compare(Left.Date,Right.Date); 
             if Result = 0 then 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    sbcState  : begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<TFileDataTestResults>.Default.Compare(Left.FileDataResult,Right.FileDataResult); 
             if Result = 0 then 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    end; 

    if assigned(Comparison) then 
    begin 
    Sort(TComparer<TFileData>.Construct(Comparison)); 

    // Control the sort order 
    if fCurrentSortedColumn = aColumn then 
     fCurrentSortAscending := not fCurrentSortAscending 
    else begin 
     fCurrentSortedColumn := aColumn; 
     fCurrentSortAscending := true; 
    end; 

    if not fCurrentSortAscending then 
     Reverse; 

    result := true; 
    end; 
end; 
1

的回答言簡意賅:

uses 
    .. System.Generics.Defaults // Contains TComparer 

myList.Sort(
    TComparer<TMyRecord>.Construct(
    function(const Left, Right: TMyRecord): Integer 
    begin 
     Result := Left.intVal - Right.intVal; 
    end 
) 
); 
相關問題