Creating a quick custom comparer for Delphi generics

Let's say you have a type,

type
  TMySecretData = record
     Timestamp: TDateTime;
     SecretInfo: string; // or some unknown type....
     class function Create(ATimestamp: TDateTime; const ASecretInfo: string): TMySecretData; static;
  end;

and you have a declaration of a list of TMySecretData:

var
  List: TList<TMySecretData>;

you have already populated this list, and now you want to sort the list.

All you have to do is create a delegated comparer with an anonymous compare function that compares one of the fields in an instance of your type with another instance:

List.Sort(TDelegatedComparer<TMySecretData>.Create(function (const Left, Right: TMySecretData): Integer begin
// Perform the comparison here
  if Left.SecretInfo < Right.SecretInfo then
     Result := -1 else
  if Left.SecretInfo > Right.SecretInfo then
     Result := 1 else
     Result := 0;
end));

TDelegatedComparer will then create an instance of the comparer: IComparer<TMySecretData> and provide that to the Sort method. One of the mistakes that can be easily overlooked is missing the "const" keyword.

Here's the complete compilable example:

uses
  System.Generics.Collections,
  System.Generics.Defaults,
  System.SysUtils,
  System.DateUtils;

type
  TMySecretData = record
     Timestamp: TDateTime;
     SecretInfo: string; // or some unknown type....
     class function Create(const ATimestamp: TDateTime; const ASecretInfo: string): TMySecretData; static;
  end;

{ TMySecretData }

class function TMySecretData.Create(const ATimestamp: TDateTime;
  const ASecretInfo: string): TMySecretData;
begin
  Result.Timestamp := ATimestamp;
  Result.SecretInfo := ASecretInfo;
end;

var
  List: TList<TMySecretData>;
  Item: TMySecretData;
begin
  List := TList<TMySecretData>.Create;

  List.Add(TMySecretData.Create(Now, 'Secret 2'));
  List.Add(TMySecretData.Create(Now, 'Secret 4'));
  List.Add(TMySecretData.Create(Now, 'Secret 1'));

  for Item in List do         // Before the sort
    begin
      WriteLn(Item.SecretInfo);
    end;

  List.Sort(TDelegatedComparer<TMySecretData>.Create(function (const Left, Right: TMySecretData): Integer begin
    if Left.SecretInfo < Right.SecretInfo then
       Result := -1 else
    if Left.SecretInfo > Right.SecretInfo then
       Result := 1 else
       Result := 0;
  end));

  for Item in List do         // After the sort
    begin
      WriteLn(Item.SecretInfo);
    end;

  List.Free;

end.

Published Tue, 21 Feb 2017 @ 9:58 AM by chuacw
Related articles: