Итерировать TObjectList
У меня есть контейнер ObjectList, и я хочу добавить внутренний итератор (шаблон посетителя), на самом деле я пытаюсь определить дубликаты в моем списке..
образец: http://pastebin.com/pjeWq2uN
этот код, чтобы дать представление о том, что я пытаюсь достичь..
TFindDuplicatesMethod = procedure(s1, s2: string) of object;
TPersonList = class(TObjectList)
public
procedure Iterate(pMethode: TFindDuplicatesMethod)
end;
procedure TPersonList.Iterate(pMethode: TFindDuplicatesMethod)
var
i: Integer;
begin
for i := 0 to Count - 1 do
pMethode(TMyClass(Items[i]).S1, {But i don't have the second parameter because
it comes from outside of PersonList Ex: OpenDialog.Files[i]})
end;
function FindDuplicate(S1, S2: string): Boolean;
begin
Result := False;
if S1 = S2 then
Result := True;
end;
begin
Files.Iterate(FindDuplicates(S1, S2));
end;
мне интересно, как ООП решить такую проблему.
заранее спасибо...
1 ответ
Хорошо, как мы обнаружили в комментариях, у нас есть 2 задачи:
- Как найти, если
TObjectList
уже содержит элемент (поэтому новый элемент является дубликатом) - Как управлять иконками файлов в
TImageList
уменьшить использование памяти и хранить только уникальные значки.
Как я уже упоминал в комментариях, вы должны задать свой второй вопрос в отдельной ветке, но я предлагаю вам добавить новые значки файлов, добавляемые в новый тип файлов mime, вместо двоичных данных значков. Здесь вы должны создать словарь по типу файла, определить тип файла и т. Д.
Как насчет дубликатов в TObjectList
, Вы, наверное, знаете, что есть generic
реализация TObjectList
- TObjectsList<T>
, Как в вашем примере вы можете определить TPersonList
как TObjectList<TPerson>
, так items
свойство всегда возвращается TPerson
экземпляр объекта.
Теперь общее задание со списками - сортировка списков. Взгляни на Sort()
метод TObjectList<T>/TList
, Имеет 2 метода перегрузки. Один из них по умолчанию, а второй занимает Comparer
в качестве параметра. На самом деле, первый метод также использует компаратор - компаратор по умолчанию. Таким образом, компаратор является реализацией IComparer<T>
интерфейс, который имеет единственный метод - function Compare(l,r : T):integer
; Обычно вы определяете этот сортировщик сравнения во время выполнения как анонимный метод перед вызовом Sort()
метод. Используя анонимный метод, вы всегда знаете, как сравнить два T
объекты, и тогда вы можете определить, какой из них "больше", чем другие, и должен быть первым в списке.
То же самое происходит и при поиске дубликатов в списке. но теперь вы должны определить, равны ли 2 объекта или нет.
Допустим, у вас есть personList : TPersonList
который содержит TPerson
экземпляров. У каждого человека есть, например, имя, фамилия, дата рождения и удостоверение личности. Конечно, по умолчанию сравнивающий ничего не знает о том, как сравнивать 2 человека. Но вы можете предоставить новый компаратор, который знает. Например, предположим, что 2 объекта равны, если их идентификаторы равны;
TPerson = class(TObject)
strict private
FName : string;
FSurname : string;
FDateOfBirth : TDateTime;
FId : string; {passport number or something else}
public
constructor Create(aID : string; aDoB : TDateTime);
property Name : string read FName write FName;
property Surname : string read FSurname write FSurname;
property DateOfBirth : TDateTime read FDateOfBirth;
property ID : string read FId;
end;
TPersonList = class(TObjectList<TPerson>)
public
constructor Create();
end;
TPerson
конструктор обычный:
constructor TPerson.Create(aID: string; aDoB: TDateTime);
begin
inherited Create();
FID := aId;
FDateOfBirth := aDoB;
end;
теперь мы должны написать TPersonList
застройщик. Как вы видете,TObejctList
Конструктор имеет несколько перегрузок. У одного из них есть Comparer
параметр. Экономит aComparer
в FComparer
поле. Теперь взгляните на Contains
метод. Он находит, список уже содержит объект или нет. Оно использует IndexOf
метод. Так что если возвращено index = 0, то список содержит наш объект.
Итак, теперь наша задача - определить новый компаратор в TPersonList
конструктор. Мы должны определить метод сравнения, затем создать объект сравнения и передать его в конструктор List.
constructor TPersonList.Create();
var comparer : IComparer<TPerson>;
comparison : TComparison<TPerson>;
begin
comparison := function(const l,r : TPerson):integer
begin
if l.ID = r.id then exit(0)
else if l.ID > r.ID then exit(-1)
else exit(1);
end;
comparer := TComparer<TPerson>.Construct(comparison);
inherited Create(comparer);
end;
чтобы проверить наш код, давайте добавим несколько человек в список.
procedure TForm2.FormCreate(Sender: TObject);
var persons : TPersonList;
function AddPerson(id : string; date : TDateTime):boolean;
var p : TPerson;
begin
p := TPerson.Create(id, date);
result := not persons.Contains(p);
if result then
persons.Add(p)
else begin
ShowMessage('list already contains person with id = ' + id);
p.Free();
end;
end;
begin
persons := TPersonList.Create();
try
AddPerson('1', StrToDate('01.01.2000'));
AddPerson('2', StrToDate('01.01.2000'));
AddPerson('3', StrToDate('01.01.2000'));
AddPerson('2', StrToDate('01.01.2000')); // we will get message here.
finally
persons.Free();
end;
end;
Итак, это обычный способ, как определить, TList
(или его потомок) содержит объект.