我写了这个函数来删除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;
你需要另一张清单。
答案 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。
自定义计数器
如果您可以编辑这些对象,则可以在没有接口的情况下执行相同的操作。将对象添加到列表时递增对象,并在删除对象时减少它。
当然,这只有在您可以为这些对象添加计数器时才有效,但在您的问题中边界并不完全清楚,所以我不知道是否允许这样做。
优点是您不需要查找其他项目,而不是在插入时,而不是在删除重复项目时。在排序列表中查找副本可能会更快(如评论中所述),但不必进行搜索就会击败最快的查找。