迭代TObjectList

S.F*_*TEH 0 delphi loops tobjectlist visitor-pattern delphi-2010

我有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;
Run Code Online (Sandbox Code Playgroud)

我想知道OOP如何解决这个问题.

提前致谢...

ter*_*ran 10

好的,正如我们在评论中发现的那样,我们有两个任务:

  1. 如何查找是否TObjectList已包含项目(因此新项目是重复的)
  2. 如何管理文件图标TImageList以减少内存使用量并仅存储唯一图标.

正如我在评论中提到的,您应该在单独的线程中询问您的第二个问题,但我建议您添加新文件图标,这取决于新文件mime-type,而不是二进制图标数据.在这里你必须创建文件类型字典,确定文件类型等等.

怎么样重复TObjectList.你可能知道,有generic的implemntation TObjectList- TObjectsList<T>.在您的示例中,您可以定义TPersonListTObjectList<TPerson>,因此items属性始终返回TPerson对象实例.

现在,通用任务与列表 - 列表排序.看一下Sort()方法吧TObjectList<T>/TList.它有2种重载方法.其中一个是默认值,第二个是Compareras参数.实际上,第一种方法也使用了比较器 - 默认比较器.所以比较器是IComparer<T>接口的实现,它具有唯一的方法 - function Compare(l,r : T):integer; 通常在调用方法之前,在运行时将此排序比较器定义为无限Sort()方法.使用你的无限方法你总是知道如何比较两个T对象,然后你可以确定它们比其他对象"更大",并且应该是列表中的第一个.

所以你在搜索列表中的重复项时遇到的情况相同.但现在你必须确定,2个对象是否相等.

让我们假设您personList : TPersonList包含TPerson实例.例如,每个人都有姓名,姓氏,出生日期和身份证明.当然,默认比较器对如何比较2个人一无所知.但你可以提供知道的新比较器.例如,假设2个对象是等于的,如果它们的ID相等;

    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;
Run Code Online (Sandbox Code Playgroud)

TPerson 通常的构造函数:

constructor TPerson.Create(aID: string; aDoB: TDateTime);
begin
    inherited Create();
    FID := aId;
    FDateOfBirth := aDoB;
end;
Run Code Online (Sandbox Code Playgroud)

现在我们要编写TPersonList构造函数.如您所见,TObejctList构造函数具有很少的重载.其中一个有Comparer参数.它节省aComparerFComparer现场.现在,看看Contains方法.它发现列表已包含对象与否.它使用IndexOf方法.因此,如果返回index = 0,则list包含我们的对象.

所以现在我们的任务是在TPersonList构造函数中定义新的比较器.我们应该定义comparsion方法,然后创建comparer对象并将其传递给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;
Run Code Online (Sandbox Code Playgroud)

为了测试我们的代码,让我们添加一些人来列出.

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;
Run Code Online (Sandbox Code Playgroud)

因此,这是如何确定TList(或其后代)是否包含对象的常用方法.

  • +1在这里付出努力.但是,@ S.FATEH您应该知道这不能回答您提出的问题.这并不是说它不是您需要的信息.就是这样.但我的观点是你提出了错误的问题.我们不得不依靠巨大的评论线来找出你真正想要的东西.您可以从中得出的教训是,询问问题而不是解决方案是值得的,并且您应该准备好及时写出好的问题.通常这意味着对现有问题进行重大编辑. (4认同)