【问题标题】:Iterate TObjectList迭代 TObjectList
【发布时间】:2013-01-04 23:26:18
【问题描述】:

我有 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;

我想知道 OOP 是如何解决此类问题的。

先谢谢了...

【问题讨论】:

  • 我正在研究 delphi 2010 David
  • 一个简单的迭代器与访问者模式无关。
  • @DavidHeffernan thamk 我的 oop 技能和我的英语一样差,所以如果你能给我一些例子,我会感谢你的帮助..
  • 这个问题的基本前提是错误的。您不能使用单次迭代来查找重复项。重复发现需要两次迭代,并精心安排。您提出的解决方案是错误的。请告诉我们您的基本目标是什么,让我们告诉您如何解决问题。
  • 事实上,您甚至没有找到重复项。重复是指列表包含多个匹配的项目。例如,一个字符串列表包含两个具有相同字符串的元素。您需要一个名为 IndexOfContains 的方法。这些方法已经存在于TList<T> 通用容器中。

标签: delphi delphi-2010 loops visitor-pattern tobjectlist


【解决方案1】:

好的,正如我们在 cmets 中发现的,我们有 2 个任务:

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

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

TObjectList 中的重复项怎么办? 您可能知道,有generic 实现TObjectList - TObjectsList<T>。在您的示例中,您可以将TPersonList 定义为TObjectList<TPerson>,因此items 属性始终返回TPerson 对象实例。

现在,带有列表的通用任务 - 列表排序。看看TObjectList<T>/TListSort() 方法。它有2个重载方法。其中之一是默认值,第二个采用Comparer 作为参数。实际上,第一种方法也使用了一个比较器——默认比较器。 所以比较器是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;

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 那么 list 包含我们的对象。

所以现在我们的任务是在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(或其后代)是否包含对象的常用方法。

【讨论】:

  • 在我对找到好的解决方案感到失望之后,我打开 stackoverflow 以查看新通知,感谢上帝,这不是新评论,而是@teran 感谢的答案,我希望这将有助于其他程序员完成此类任务。
  • +1 表示在这里付出了努力。但是,@S.FATEH 您应该知道这并不能回答您提出的问题。这并不是说这不是您需要的信息。正是这样。但我的意思是你问错了问题。我们不得不依靠庞大的评论线索来确定您真正想要的内容。您可以从中吸取的教训是,提出问题而不是解决方案是值得的,并且您应该准备好花时间写出好问题。这通常意味着对现有问题进行重大修改。
猜你喜欢
  • 2021-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多