unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Generics.Collections, Generics.Defaults, StdCtrls;

type
  TForm3 = class(TForm)
    btCustomCount: TButton;
    InMemo: TMemo;
    OutMemo: TMemo;
    btDefaultCount: TButton;
    procedure btCustomCountClick(Sender: TObject);
    procedure btDefaultCountClick(Sender: TObject);
  private
    { Private declarations }
    procedure NumberInstances(const AComparer: IEqualityComparer<String>);
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

// BeginExample: Generics_Defaults_TEqualityComparer
// Class: Generics.Defaults.TEqualityComparer
// Method: Generics.Defaults.TEqualityComparer.Equals
// Method: Generics.Defaults.TEqualityComparer.GetHashCode
// Method: Generics.Defaults.TEqualityComparer.Default

// BeginCode
{
This example demonstrates the usage of TDelegatedEqualityComparer and
anonymous methods in order to create a custom comparer.
The example assumes two memos and two buttons are present on the form.
}

type
  TCustomEqualityComparer = class(TEqualityComparer<String>)
  public
    function Equals(const Left, Right: String): Boolean; override;
    function GetHashCode(const Value: String): Integer; override;
  end;

{ TCustomEqualityComparer }

function TCustomEqualityComparer.Equals(const Left, Right: String): Boolean;
begin
  { Make a case insensitive comparison }
  Result := CompareText(Left, Right) = 0;
end;

function TCustomEqualityComparer.GetHashCode(const Value: String): Integer;
begin
  { Generate a hash code. Simply return the length of the string
    as its hash code }
  Result := Length(Value);
end;

procedure TForm3.NumberInstances(const AComparer: IEqualityComparer<String>);
var
  Dictionary: TDictionary<String, Cardinal>;
  I: Integer;
  AString: String;
begin
  { Create a new dictionary of string/cardinal }
  Dictionary := TDictionary<String, Cardinal>.Create(AComparer);

  { Populate the dictionary with strings in the memo }
  for I := 0 to InMemo.Lines.Count - 1 do
  begin
    { Get the list from the memo }
    AString := InMemo.Lines[I];

    { If the string is already in the dictionary, increase its count
      by one. Otherwise add it with one by default.
    }
    if Dictionary.ContainsKey(AString) then
      Dictionary[AString] := Dictionary[AString] + 1
    else
      Dictionary.Add(InMemo.Lines[I], 1);
  end;

  { Copy the list with numbers to the memo }
  OutMemo.Clear;

  { Now populate the out memo with string and the number of times it was
    present in the initial memo}
  for AString in Dictionary.Keys do
    OutMemo.Lines.Add(AString + ':' + UIntToStr(Dictionary[AString]));

  { Free resources }
  Dictionary.Free();
end;

procedure TForm3.btDefaultCountClick(Sender: TObject);
begin
  { Use the default provided equality comparer }
  NumberInstances(TEqualityComparer<String>.Default);
end;

procedure TForm3.btCustomCountClick(Sender: TObject);
begin
  { Use the cutom generated equality comparer }
  NumberInstances(TCustomEqualityComparer.Create());
end;
// EndCode
// EndExample: Generics_Defaults_TEqualityComparer

end.
