2012-11-06 49 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 
) 
); 
相关问题