Вопрос

i have ObjectList container and i want to add an internal iterator (Visitor Pattern) in fact i'm attempting to determine duplicates in my List..

a sample: http://pastebin.com/pjeWq2uN

this code to provide an insight of what i'm trying to achieve..

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;

i'm wondering how OOP solve such problem.

thank's in advance...

Это было полезно?

Решение

Ok, as we found in comments, we have 2 tasks:

  1. How to find if TObjectList already contains an item (so new item is an duplicate)
  2. How to manage file icons in TImageList to reduce memory usage and store only unique icons.

As I mentioned in comments, you should ask about your second question in separate thread, but I suggest you to add new files icons depeding on new file mime-type, instead of binary icon data. Here you have to create file-type dictionary, determine file-type and so on..

What about duplicates in TObjectList. You probably know, that there is generic implemntation of TObjectList - TObjectsList<T>. As in your example you can define TPersonList as TObjectList<TPerson>, so items property always returns TPerson objects instance.

now, generic task with lists - list sorting. Take a look at Sort() method of TObjectList<T>/TList. It has 2 overload methods. One of them is default, and second takes an Comparer as parameter. Actually, the first method also uses an comparer - default comparer. So comparer is an implemntation of IComparer<T> interface wich has the only method - function Compare(l,r : T):integer; Usually you define this sort-comparer at runtime as anonimous method, before calling the Sort() method. Using you anonimous method you always know how to compare two T-typed objects, and then you can determine wich of them is "greater" than other, and should be the first in list.

so the same situation you have while searching for duplicates in list. but now you have to determine, are 2 objects equal or not.

Let us suppose you have personList : TPersonList wich contains TPerson instances. Each person has, for exmaple, name, surname, date of birth and ID. Of course default comparer knows nothing about how to compare 2 persons. But you can provide new comparer wich knows. For example, let suppose 2 objects are equals, if their IDs are equal;

    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 is usual:

constructor TPerson.Create(aID: string; aDoB: TDateTime);
begin
    inherited Create();
    FID := aId;
    FDateOfBirth := aDoB;
end;

now we have to write TPersonList contructor. As you can see,TObejctList constructor has few overloads. One of them has Comparer parameter. It saves aComparer to FComparer field. Now, take a look at Contains method. It finds does list already contain object or not. It uses IndexOf method. So if returned index = 0 then list contains our object.

So now our task is to define new comparer in TPersonList constructor. We should define comparsion method, then create comparer object and pass it to List contructor.

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;

to test our code, lets add some persons to list.

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;

So, this is the usual way how to determine if TList (or its descendant) contains object.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top