问题
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?
回答1:
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;
回答2:
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;
回答3:
If you don't have an instance to search for, you have to do your own search. There are three basic ways to do this:
- Binary search: Implement your own binary search. This will only work if the list is sorted.
- Linear search: Implement your own linear search. This will always work, but on large lists it's significantly slower than a binary search.
- Dictionary lookup: Maintain a
TDictionary<string, TActivityCategory>
alongside the list. No searching required, though you need to write some code to keep the two in sync.
来源:https://stackoverflow.com/questions/8054558/how-do-i-search-a-generic-tlistt-collection