tags:

views:

278

answers:

2

I am trying to remove duplicates in my listview.

This function:

procedure RemoveDuplicates(const LV:TbsSkinListView);
var 
  i,j: Integer;
begin   
  LV.Items.BeginUpdate;  
  LV.SortType := stText;   
  try
    for i := 0 to LV.Items.Count-1 do  
    begin
      for j:=i+1 to LV.Items.Count-1 do
      begin  
        if  SameText(LV.Items[i].SubItems[0], LV.Items[j].SubItems[0]) and
        SameText(LV.Items[i].SubItems[1], LV.Items[j].SubItems[1]) and
        SameText(LV.Items[i].SubItems[2], LV.Items[j].SubItems[2]) and
        SameText(LV.Items[i].SubItems[3], LV.Items[j].SubItems[3])  then     
        LV.Items.Delete(j);
      end;   
    end;   
  finally
    LV.SortType := stNone;
    LV.Items.EndUpdate;   
  end;
  ShowMessage('Deleted');    
end;

does not delete the duplicates. What is wrong with it?

+2  A: 

The easiest way to do this in Delphi IMO is to do it like this....

  • Create a function that creates a hashkey for your matching critera i.e. add all the text you want to match together and then hash it.
  • use the hash as a key in a list
  • navigate your listview and remove any item that is not in the list.

Pseudo Code....(untested)

var
  hash : integer;
  i : integer;
  list : SomeGenericList; // some generic list to contain your hash.
Begin
    list = SomeGenericList.Create;
    for i := pred(lv.Items.Count) downto 0
    begin
        hash := GetHashValue(lv.items[i]);
        if List.Contains(hash)
        begin
            lv.Items.Delete(i);
        end else
        begin
            List.Add(hash);
        end;
    end;
    list.free;
end;

Shame delphi does not have Linq type functionality, this would be a really simple task using that.

Tim Jarvis
+4  A: 

At a guess, since you haven't mentioned what is going wrong, I would think that is has to do with the fact that i and j are invalid after you have deleted an item because you are counting UP.

A better idea would be to count down instead:

procedure RemoveDuplicates(const LV:TbsSkinListView);
var 
  i,j: Integer;
begin   
  LV.Items.BeginUpdate;  
  LV.SortType := stText;   
  try
    for i := LV.Items.Count-1 downto 0 do // <- this loop now counts _down_
    begin
      for j:= LV.Items.Count-1 downto i+1 do // <- this loop now counts _down_
      begin  
        if  SameText(LV.Items[i].SubItems[0], LV.Items[j].SubItems[0]) and
            SameText(LV.Items[i].SubItems[1], LV.Items[j].SubItems[1]) and
            SameText(LV.Items[i].SubItems[2], LV.Items[j].SubItems[2]) and
            SameText(LV.Items[i].SubItems[3], LV.Items[j].SubItems[3]) then     
          LV.Items.Delete(j);
      end;   
    end;   
  finally
    LV.SortType := stNone;
    LV.Items.EndUpdate;   
  end;
  ShowMessage('Deleted');    
end;
Nat
thanks it worked :) , i did mistake by coming top to down thanks again :)
radick