Подтвердить что ты не робот

Как отсортировать общий список с помощью пользовательского сопоставления?

Я вроде как новичок Delphi, и я не понимаю, как вызывается метод Sort TList Records для сортировки записей по возрастанию целочисленного значения. У меня есть запись, подобная следующей:

 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;

Я пробовал разные способы вызова функции, всегда получая некоторую ошибку...

4b9b3361

Ответ 1

Перегрузка 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 как анонимный метод, но вы также можете использовать обычную функцию non-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;

Ответ 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);

Ответ 3

Я хочу поделиться своим решением (на основе ввода, который я собрал здесь).

Это стандартная настройка. Класс filedata, который содержит данные одного файла в общем 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;

Ответ 4

Краткий ответ:

//TComparer --> uses System.Generics.Defaults
myList.Sort(TComparer<TMyRecord>.Construct(function(const Left, Right: TMyRecord): Integer
      begin
         Result := Left.intVal- Right.intVal;
      end));