从List中删除重复项

时间:2012-10-23 08:56:41

标签: delphi list duplicates delphi-xe2 tlist

我写了这个函数来删除TList后代的重复项,现在我想知道这是否会在某些条件下给我带来问题,以及它如何在性能方面表现出色。

它似乎适用于Object Pointers

function TListClass.RemoveDups: integer;
var
  total,i,j:integer;
begin
  total:=0;
  i := 0;
  while i < count do begin
    j := i+1;
    while j < count do begin
      if items[i]=items[j] then begin
       remove(items[j]);
       inc(total);
      end
      else
        inc(j);
    end;
    inc(i);
  end;
  result:=total;
end;

更新 这会更快吗?

function TDrawObjectList.RemoveDups: integer;
var
  total,i,j:integer;
  templist:TLIST;
begin
  templist:=TList.Create;
  total:=0;
  i := 0;
  while i < count do
    if templist.IndexOf(items[i])=-1 then begin
      templist.add(i);
      inc(i);
    end else begin
      remove(items[i]);
      inc(total);
    end;
  result:=total;
  templist.Free;
end;

你需要另一张清单。

2 个答案:

答案 0 :(得分:1)

如上所述,解决方案是O(N ^ 2),这使得它在大量项目(1000s)上非常慢,但只要计数保持低,这是最好的选择,因为它简单易行。哪里有预先排序,其他解决方案需要更多代码,更容易出现实施错误。

这可能是用不同的,更紧凑的形式编写的相同代码。它遍历列表的所有元素,并为每个元素删除当前元素右侧的重复项。只要在反向循环中完成移除就是安全的。

function TListClass.RemoveDups: Integer;
var
  I, K: Integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do //Compare to everything on the right
  for K := Count - 1 downto I+1 do //Reverse loop allows to Remove items safely
    if Items[K] = Items[I] then
    begin
      Remove(Items[K]);
      Inc(Result);
    end;
end;

如果你真的最终获得5000个项目列表,我建议将优化保留到以后的时间。此外,如上所述,如果您在列表中添加项目时检查重复项,则可以保存:

  • 检查重复项是否及时分发,因此用户不会注意到
  • 如果发现重复,你可以提前退出

答案 1 :(得分:1)

只是假设:

接口

如果TInterfaceList中的接口对象在该列表中仅 ,则可以检查对象的引用计数。只需向后循环列表并删除所有带有引用计数的对象&gt; 1。

自定义计数器

如果您可以编辑这些对象,则可以在没有接口的情况下执行相同的操作。将对象添加到列表时递增对象,并在删除对象时减少它。

当然,这只有在您可以为这些对象添加计数器时才有效,但在您的问题中边界并不完全清楚,所以我不知道是否允许这样做。

优点是您不需要查找其他项目,而不是在插入时,而不是在删除重复项目时。在排序列表中查找副本可能会更快(如评论中所述),但不必进行搜索就会击败最快的查找。