Итерация 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;

мне интересно, как ООП решает такую ​​проблему.

заранее спасибо...


person S.FATEH    schedule 04.01.2013    source источник
comment
я работаю над delphi 2010 Дэвид   -  person S.FATEH    schedule 04.01.2013
comment
Простой итератор не имеет ничего общего с шаблоном посетителя.   -  person Uwe Raabe    schedule 04.01.2013
comment
@DavidHeffernan thamk, мои навыки работы с оператором хуже, чем мой английский, поэтому, пожалуйста, если бы вы могли привести мне какой-нибудь пример, я буду благодарен за вашу помощь ..   -  person S.FATEH    schedule 04.01.2013
comment
@UweRaabe да, вы правы, я просто следую туто по ссылке   -  person S.FATEH    schedule 04.01.2013
comment
Прежде всего вам нужно переписать код, чтобы использовать универсальные контейнеры в Generics.Collections. Это позволяет вам остановить кастинг везде.   -  person David Heffernan    schedule 04.01.2013
comment
Основная посылка этого вопроса неверна. Вы не можете использовать одну итерацию для поиска дубликатов. Повторное обнаружение требует двойной итерации и тщательно организовано. Предложенное вами решение неверно. Пожалуйста, сообщите нам, какова ваша основная цель, и позвольте нам рассказать вам, как решить проблему.   -  person David Heffernan    schedule 04.01.2013
comment
хорошо, я подготовлю образец...   -  person S.FATEH    schedule 04.01.2013
comment
Фактически, вы даже не находите дубликаты. Дубликаты — это когда список содержит несколько совпадающих элементов. Например, список строк, содержащий два элемента с одной и той же строкой. Вам нужен метод с именем IndexOf или Contains. Эти методы уже существуют в TList<T> универсальном контейнере.   -  person David Heffernan    schedule 04.01.2013
comment
Начал писать ответ, но бросил. Вопрос слишком широк в его нынешнем виде.   -  person David Heffernan    schedule 04.01.2013
comment
@David, не сдавайся, вопрос о повторении ObjectList и проверке на наличие дубликатов, вот и все ...   -  person S.FATEH    schedule 04.01.2013
comment
@ S.FATEH Я не решаюсь писать это, потому что это не имеет прямого отношения к вашему вопросу, и я рискую получить отрицательные голоса. Небольшое замечание: три строки в вашей функции FindDuplicate можно заменить одной строкой: Result := (S2 = S1); Ваш код FindDuplicate отлично работает, но, на мой взгляд, одна строка более читабельна. (Скобки необязательны, но помогают сделать одну строку более читаемой.)   -  person RobertFrank    schedule 04.01.2013
comment
@S.FATEH Код, который вы написали, не будет проверять наличие дубликатов. Он выполняет линейный поиск. Честно говоря, я понятия не имею, что вы пытаетесь сделать. Я знаю, что английский не ваш родной язык, но ваш английский на самом деле в порядке. Вам нужно немного замедлиться и описать свою проблему. Не говорите нам о предложенном вами решении. Расскажите нам о проблеме. Мы можем рассказать вам, как это решить.,   -  person David Heffernan    schedule 04.01.2013
comment
@ Дэвид, я делаю все возможное, чтобы найти проблему и решить ее, но я всегда захожу в тупик, поэтому я публикую свой вопрос, пожалуйста, взгляните на pastebin.com/pjeWq2uN и забудьте о добавлении внутренней итерации...   -  person S.FATEH    schedule 04.01.2013
comment
Извините, я не могу ответить на вопрос, основанный на вставке за пределами сайта. Возможно, кто-то еще будет. На мой взгляд, вы недостаточно стараетесь задать хороший вопрос. Извините, если это звучит резко. Вам нужно полностью переписать свой вопрос, чтобы мы могли его понять.   -  person David Heffernan    schedule 04.01.2013
comment
Я согласен с @DavidHeffernan - проблема не ясна. У вас есть TObjectList, и вы хотите найти повторяющиеся записи; столько мы можем собрать. Вопрос в моей голове, что вы хотите делать, когда вы найдете их. Даже если бы приведенный выше код был реализован для работы, он ничего не сделал бы - логическое значение, которое помечало бы дубликат, не используется; никаких действий не предпринимается. Вы хотите удалить дубликаты из списка?   -  person J...    schedule 04.01.2013
comment
Кроме того, здесь ваш метод TFindDuplicates является procedure of object, но вы передаете FindDuplicates, который является обычным методом (то есть: не of object) и также является не процедурой, а функцией. Один из двух должен быть изменен для компиляции.   -  person J...    schedule 04.01.2013
comment
Читая это дальше, возможно, вы не ищете дубликаты в самом списке, а скорее пытаетесь найти (искать) элемент списка, который соответствует объекту или другому идентификатору, полученному в другом месте?   -  person J...    schedule 04.01.2013
comment
я не хочу находить дубликаты в TObjectList, я хочу удалить дубликаты в своем ImageList, поэтому я использую TObjectList в качестве структуры данных, которая содержит дескриптор Icon (hicon), если значок всегда добавляется в imaglist, я не буду добавлять его снова, я просто укажу к индексу этого в любом случае спасибо за ваше терпение за сотрудничество ...   -  person S.FATEH    schedule 04.01.2013
comment
Как я понял после прочтения примера кода в pastebin, ваша проблема заключается в поиске дубликатов в TImageList. У вас есть список файлов, и каждый файл имеет свою иконку (HICON). Вы собираетесь заполнить TImageList этими значками и вернуть ImageIndex. Итак, если ImageList уже имеет значок, подобный вашему новому файлу, вы хотите использовать этот существующий ImageIndex, не добавляя новый значок в ImageList. так. вопрос: это ваша проблема или нет? если да, спросите о вашей конкретной проблеме. если нет, то зачем вы вставили сюда код патебина?   -  person teran    schedule 04.01.2013
comment
@teran именно такая ситуация   -  person S.FATEH    schedule 04.01.2013
comment
@S.FATEH хорошо, тогда у меня есть один вопрос и одно предложение. вопрос: Сколько файлов у вас в списке, стоит ли это усложнение? предложение: сравнение двоичных данных значка дорого для этой задачи. Другой способ — получить тип файла (MIME-тип), поскольку вы знаете, что все файлы jpeg имеют одинаковую иконку и т. д., за исключением файлов exe и lnk. Итак, предложение - заполнить список изображений в зависимости от типа файла вместо двоичных данных значка.   -  person teran    schedule 04.01.2013
comment
для вашего вопроса количество файлов, определенных во время выполнения, может быть от 1 до 10 до 100, ваше предложение действительно соответствует моим потребностям, я приму ваш совет... но как насчет выбора трудного пути :) код pastebin...   -  person S.FATEH    schedule 04.01.2013


Ответы (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. Итак, если возвращаемый индекс = 0, то список содержит наш объект.

Итак, теперь наша задача — определить новый компаратор в конструкторе TPersonList. Мы должны определить метод сравнения, затем создать объект сравнения и передать его конструктору списка.

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 (или его потомок) объект.

person teran    schedule 04.01.2013
comment
после того, как я был разочарован, найдя хорошее решение, я открываю stackoverflow, чтобы увидеть новое уведомление, и, слава богу, это не новый комментарий, а ответ @teran, спасибо, и я надеюсь, что это поможет другим программистам в таких задачах. - person S.FATEH; 04.01.2013
comment
+1 за то, что приложил сюда усилия. Однако, @S.FATEH, вы должны знать, что это не отвечает на заданный вами вопрос. Это не значит, что это не та информация, которая вам нужна. Это именно так. Но я хочу сказать, что вы задали неправильный вопрос. Нам пришлось полагаться на огромное количество комментариев, чтобы выяснить, что вы действительно хотели. Урок, который вы можете извлечь из этого, заключается в том, что стоит спрашивать о проблемах, а не о решениях, и что вы должны быть готовы потратить время на написание хороших вопросов. И часто это означает внесение значительных изменений в существующие вопросы. - person David Heffernan; 05.01.2013