39

我有点像 Delphi 新手,我不明白如何调用 TList of Records 的 Sort 方法来通过升序整数值对记录进行排序。我有如下记录:

 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;

我尝试了不同的调用函数的方法,总是得到一些错误......

4

4 回答 4

62

Sort您应该使用的重载是这个:

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

现在,您可以IComparer<TMyRecord>通过调用TComparer<TMyRecord>.Construct. 像这样:

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函数编写为匿名方法,但您也可以使用普通的旧式非 OOP 函数或对象的方法。

比较函数的一个潜在问题是您可能会遇到整数溢出。所以你可以改用默认的整数比较器。

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;
于 2012-11-06T13:45:47.990 回答
15

简洁的答案:

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

myList.Sort(
  TComparer<TMyRecord>.Construct(
    function(const Left, Right: TMyRecord): Integer
    begin
      Result := Left.intVal - Right.intVal;
    end
  )
);
于 2017-09-17T14:38:07.477 回答
2

我想分享我的解决方案(基于我在这里收集的输入)。

这是一个标准设置。一个文件数据类,它在通用 TObjectList 中保存单个文件的数据。该列表有两个私有属性 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;
于 2017-06-21T11:04:53.170 回答
0

我发现了一个更简单的修改排序函数来按字母顺序排列记录的 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);
于 2014-11-19T05:41:07.727 回答