Итерировать 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 задачи:

  1. Как найти, если TObjectList уже содержит элемент (поэтому новый элемент является дубликатом)
  2. Как управлять иконками файлов в 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 (или его потомок) содержит объект.

Другие вопросы по тегам