Solved

How do I find duplicate entries in a TSringlist

Posted on 2002-05-12
11
258 Views
Last Modified: 2010-04-04
I would like to be able to search through a stringlist for duplicate entries and add an associated number, for example.

item number    quantity
1                  5
2                  4
3                  2
1                  3

How do I search through this list for each enrty of item number 1. When item number 1 is found I wish to add each quantity to get the total quantity. The resultant list will be.

item number    quantity
1                  8
2                  4
3                  2

Thankyou for your help,
Ivan
0
Comment
Question by:icarey
  • 3
  • 2
  • 2
  • +3
11 Comments
 
LVL 1

Expert Comment

by:MBo
ID: 7005235
I've used tstringlist.objects to store quantity of equal items.

It isn't clear from question:
1) Is quantity defined initially or not?
2) Is it necessary add quantity number in strings?

procedure TForm1.Button1Click(Sender: TObject);
var i,j:integer;
sl:tstringlist;
begin
randomize;
sl:=tstringlist.create;
for i:=1 to 20 do
  sl.add(IntToStr(Random(5)));
memo1.lines.AddStrings(sl);
memo1.lines.Add('-------------');
i:=0;
while i<sl.count do begin
  j:=sl.IndexOf(sl[i]);
  if j=i then begin
    sl.Objects[i]:=pointer(1);
    inc(i);
  end
  else begin
    sl.Objects[j]:=pointer(Integer(sl.Objects[j])+1);
    sl.Delete(i);
  end;
end;
sl.Sorted:=true;//if you need
for i:=0 to sl.Count-1 do
  memo1.Lines.Add(sl[i]+#9+IntToStr(Integer(sl.Objects[i])));
sl.free;
end;
0
 

Expert Comment

by:BaSoAM
ID: 7005318
Hey there!...

Load the Tstrings into a listbox1 and then call this procedure.  Change the properties of listbox1 to sorted.  This will cause the values to group together.  

I'm guessing Item Numbers and Quantity Numbers were in the same string and separated by a ';' sign.

Goodluck...


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    ListBox2: TListBox;
    ListBox3: TListBox;
    ListBox4: TListBox;
    ListBox5: TListBox;
    ListBox6: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
count1, m, num1, j, num2, temp1 : integer;
itemnumber1, quantity1, itemnumber2, quantity2, word1, word2, wordline1, wordline2 : string;
begin
  num1 := 0;
  num2 := 0;
  count1 := 0;
  word1 := '';
  word2 := '';
  WHILE count1 <= (listbox1.Items.count-2) DO BEGIN
    //Wordline stores the active line as a string.
    wordline1 := listbox1.Items[count1];
    wordline2 := listbox1.Items[(count1 + 1)];
      FOR m := 1 TO length(wordline1) DO BEGIN
        //Search and extract item-number and quantity.
        IF wordline1[m] = ';' THEN BEGIN
          IF num1 = 0 THEN BEGIN
          itemnumber1 := word1;
          num1 := num1 + 1;
          word1 := '';
          END
          ELSE IF num1 = 1 THEN BEGIN
          quantity1 := word1;
          num1 := 0;
          word1 := '';
          END;
        END
        ELSE BEGIN
        word1 := word1 + wordline1[m];
        END;
      END;
      //Check next line.
      FOR j := 1 TO length(wordline2) DO BEGIN
        //Search and extract item-number and quantity.
        IF wordline2[j] = ';' THEN BEGIN
          IF num2 = 0 THEN BEGIN
          itemnumber2 := word2;
          num2 := num2 + 1;
          word2 := '';
          END
          ELSE IF num2 = 1 THEN BEGIN
          quantity2 := word2;
          num2 := 0;
          word2 := '';
          END;
        END
        ELSE BEGIN
        word2 := word2 + wordline2[j];
        END;
      END;
      //Fill listbox1.
      IF itemnumber1 = itemnumber2 THEN BEGIN
      temp1 := strtoint(quantity1) + strtoint(quantity2);
      quantity1 := inttostr(temp1);
      listbox1.items[count1] := itemnumber1 + ';' + quantity1 + ';';
      listbox1.Items.delete(count1 + 1);
      count1 := count1 - 1;
      END
      ELSE IF itemnumber1 <> itemnumber2 THEN BEGIN
      listbox1.items[count1] := itemnumber1 + ';' + quantity1 + ';';
      END;
      //Move to next line.
      count1 := count1 + 1;
  END;
end;

end.
0
 

Expert Comment

by:BaSoAM
ID: 7005415
Sorry icarey,

I forgot to metion add a ';' at the end also.  Input should look like this...

1;5;
2;4;
3;2;
1;3;

If you need further help please ask...
0
 
LVL 4

Expert Comment

by:nestorua
ID: 7006793
HI, icarey,
Kind of the following:

SL:=TStringList.Create;
for i:=0 to SLwithDupl.Count-1 do
 begin
  j:=SL.Index(SLwithDupl[i]);
 if j=-1
  then SL.Add(SLwithDupl[i] "and" its quantity)
  else SL[j].quantity:=SL[j].quantity+SLwithDupl[i].quantity;
 end;
That's all. It's not the code, of course, cause I don't know how you create and insert the quantity (what kind of object
you use for that). You must convert what I said in the
SL.Objects[..] and so on.
Sincerely,
Nestorua.
0
 
LVL 2

Expert Comment

by:mikepj
ID: 7007441
Hi,

I do a lot of this kind of work so I have a ready-made class which I use for this kind of work.

Nice things about it:

- you don't need to worry about finding the item in the list because that's automatic
- it's easy to get the info out

You use it something like this:

with TTotalingStringList.Create do
  try
    AddToItem('mike',5);
    AddToItem('joe',1);
    AddToItem('dilbert',5);
    AddToItem('dilbert',2);

    ShowMessage(inttostr(TotalForItem('dilbert')));
  finally
    Free;
  end;

MP

unit uTotalingStringList;

interface

uses
  Classes,

  uHandy;

type
  TTotalingStringList=class(TStringList)
    public
      constructor Create;
      function AddToItem(sItem:string;iAmt:LongInt):LongInt;
      function TotalForItem(sItem:string):LongInt;
    end;

implementation

constructor TTotalingStringList.Create;
begin
  inherited;

  Duplicates:=dupError;
end;

function TTotalingStringList.AddToItem(sItem:string;iAmt:LongInt):LongInt;
var
  iFound:integer;
begin
  iFound:=IndexOf(sItem);
  if iFound>=0 then
    begin
      Result:=LongInt(Objects[iFound])+iAmt;
      Objects[iFound]:=Pointer(Result);
    end
    else
    begin
      AddObject(sItem,Pointer(iAmt));
      Result:=iAmt;
    end;
end;

function TTotalingStringList.TotalForItem(sItem:string):LongInt;
var
  iFound:integer;
begin
  iFound:=IndexOf(sItem);
  if iFound>=0 then
    Result:=LongInt(Objects[iFound])
    else
    Result:=0;
end;

end.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 3

Author Comment

by:icarey
ID: 7007844
MBo
Let me explain a little better.

I have a comma delimited text file which I load in to a TSrtingList.
In it I have say:
'Hammer,5'
'Wrench,4'
'Screwdriver,2'
'Hammer,3'

I would now like to search through this list for each enrty of an item. For example in the list above I would like to be able to produce a list with no duplicate entries for Hammer and add the total quantity numbers.
The resulting list that I will save to a new comma delimited text file will be:

'Hammer,8'
'Wrench,4'
'Screwdriver,2'

Note: now we only have one entry for Hammer with a total quantity of 8

I hope this explains better.

Thanks to all
Ivan
0
 
LVL 1

Accepted Solution

by:
MBo earned 121 total points
ID: 7008147
OK. Corrected variant.

procedure TForm1.Button1Click(Sender: TObject);
var i,j:integer;
sl:tstringlist;

function SameName(const I1,I2:Integer):boolean;
begin
//this function from sysutils ignores case
//if case sensitivity is necessary, use next commented lines
//Result:=Copy(sl[i1],1,pos(',',sl[i1])-1)=
//  Copy(sl[i2],1,pos(',',sl[i2])-1);

Result:=SameText(Copy(sl[i1],1,pos(',',sl[i1])-1),
  Copy(sl[i2],1,pos(',',sl[i2])-1));
end;

procedure Join(const Src,Dst:Integer);
var i,i1,i2:integer;
begin
i:=pos(',',sl[Dst]);
i1:=StrToInt(Copy(sl[Dst],i+1,Length(sl[Dst])-i));
i2:=StrToInt(Copy(sl[Src],i+1,Length(sl[Src])-i));
sl[Dst]:=Copy(sl[Dst],1,i)+IntToStr(i1+i2);
sl.Delete(Src);
end;

begin
sl:=tstringlist.create;
stemp:=tstringlist.create;
sl.loadfromfile('e:\ww.txt');
i:=0;
while i<sl.count do begin
  j:=0;
  while j<i do begin
    if SameName(i,j) then begin
      Join(i,j);
      Dec(i);
      Break;
    end;
    inc(j);
  end;
  inc(i);
end;
sl.savetofile('e:\ww1.txt');
sl.free;
end;


In some spaces occur in input file ( Hammer,  5)
use Trim in front of Copy or I can write example using CommaText (slower for long files)


0
 
LVL 1

Expert Comment

by:SBSen
ID: 7008262
Hi icarey,

Load the text file into a list box
and copy this code button click...

You can get the result!

bye
SBSen.

procedure TForm1.Button1Click(Sender: TObject);
var
     St : TStringList;
     Idx,Del : Integer;
     Nm,Val : String;
begin
     St := TStringList.Create;
     for Idx := 0 to ListBox1.Items.Count-1 do
     begin
          Del := LastDelimiter(',',ListBox1.Items[Idx]);
          if Del > 0 then
               begin
                    Nm := Copy(ListBox1.Items[Idx],0,LastDelimiter(',',ListBox1.Items[Idx])-1);
                    Val := Copy(ListBox1.Items[Idx],LastDelimiter(',',ListBox1.Items[Idx])+1,MaxInt);
                    if st.Values[Nm] = EmptyStr then
                         st.Add(Nm+'='+Val)
                    else
                         try
                              st.Values[Nm] := IntToStr(StrToInt(st.Values[Nm])+ StrToInt(Val));
                         except
                              ShowMessage('Econversion Error');
                         end;
               end;
     end;
     ShowMessage(St.Text);
end;
0
 
LVL 1

Expert Comment

by:SBSen
ID: 7008352
hi,
Correction!!
'Hammer,5' if have upper quotes "'" in each string then there will be a problem we have check
Val := Copy(ListBox1.Items[Idx],LastDelimiter(',',ListBox1.Items[Idx])+1,MaxInt);
Val[Pos(',',Val)] := ' ';

one more sugession instead of , u can use =
ie Hammer=5
u can use Names and values of TStrings
or manupulate with TInifile

bye
SBSen.
0
 

Expert Comment

by:BaSoAM
ID: 7010258
icarey?...  
0
 
LVL 3

Author Comment

by:icarey
ID: 7013074
Thanks to all for helping
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi XE2 application frozen on Windows 10 10 277
Strange code, can use it, but i cant figure out what it does. 3 54
FMX enumerated colours 2 84
LAN or WAN ? 11 82
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
As a trusted technology advisor to your customers you are likely getting the daily question of, ‘should I put this in the cloud?’ As customer demands for cloud services increases, companies will see a shift from traditional buying patterns to new…

896 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now