Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I search a generic TList<T> collection? [duplicate]

Possible Duplicate:
How can I search a generic TList for a record with a certain field value?

I have a collection of

TList<TActivityCategory>

TActivityCategory has a Name property of type string and I want to search the TList using the Name property.

I see BinarySearch in the TList<> but that would require an instance of TActivityCategory. I just want to pass the string for a name.

How would I go about doing this?

like image 587
Thomas Jaeger Avatar asked Nov 08 '11 17:11

Thomas Jaeger


2 Answers

When you create the list you can pass in a comparer. There are some comparer classes in the Generics.Defaults unit where you can pass in some anonymous method to compare two elements. They are used for several methods like IndexOf, Contains or Sort.

Example:

uses
  Generics.Defaults,
  Generics.Collections;

type
  TActivityCategory = class
  private
    FName: string;
  public
    constructor Create(const Name: string);
    property Name: string read FName write FName;
  end;

constructor TActivityCategory.Create(const Name: string);
begin
  FName := Name;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  activities: TList<TActivityCategory>;
  search: TActivityCategory;
begin
  activities := TObjectList<TActivityCategory>.Create(
    TDelegatedComparer<TActivityCategory>.Create(
      function(const Left, Right: TActivityCategory): Integer
      begin
        Result := CompareText(Left.Name, Right.Name);
      end));

  activities.Add(TActivityCategory.Create('Category B'));
  activities.Add(TActivityCategory.Create('Category C'));
  activities.Add(TActivityCategory.Create('Category A'));

  search := TActivityCategory.Create('Category C');
  if activities.Contains(search) then
    ShowMessage('found');

  ShowMessageFmt('Index: %d', [activities.IndexOf(search)]);
  activities.Sort;
  ShowMessageFmt('Index: %d', [activities.IndexOf(search)]);


  search.Name := 'Category D';
  if not activities.Contains(search) then
    ShowMessage('not found');

  search.Free;
  activities.Free;
end;
like image 131
Stefan Glienke Avatar answered Oct 02 '22 22:10

Stefan Glienke


To be perfectly frank, and considering all the boiler plate required for a comparer based approach, it may just be simplest to write your own search routine:

type
  TActivityCategoryList = class(TList<TActivityCategory>)
  public
    function Find(const Name: string): Integer;
  end;

function TActivityCategoryList.Find(const Name: string): Integer;
begin
  for Result := 0 to Count-1 do
    if Self[Result].Name=Name then
      exit;
  Result := -1;
end;
like image 40
David Heffernan Avatar answered Oct 02 '22 23:10

David Heffernan