delphiappendtstringlist

How to append to a given string in a Tstringlist


I'm creating lists of email addresses implemented as csv strings in a TStringlist by appending each new email to an existing csv string. If the csv string in MyStringlist[0] already contains the email I'm about to add then I'll append it to MyStringlist[1]. If that string also already contains it then I'll append it to MyStringlist[2] and so on until I find a string that doesn't contain it.

The problem occurs if, for example, MyStringlist[0] and MyStringlist[1] both contain the email I want to append but MyStringlist[2] doesn't yet exist so it can't be appended to.

e.g. I might need to add 'a.co.uk' to MyStringlist that already contains the strings below.

MyStringlist[0] -> a.co.uk, f.co.uk, h.co.uk, k.co.uk
MyStringlist[1] -> d.co.uk, a.co.uk, g.co.uk

I created a procedure to append an email to a string at a given index or create a new string in the stringlist if necessary.

Is this code the correct way to do it or are there functions I should use to do this in a simpler way - or maybe in a more robust way?

Procedure created

procedure AppendToStringListItem(TheStringList: Tstringlist;
                                 Index : integer;
                                 StringToAppend : string);
var i : integer;
begin
if Index >= 0 then
  begin
  if TheStringList.count -1 < index then //not enough strings
    begin
    for i := 1 to index - TheStringList.Count  do  //add a blank string
       TheStringList.add('');
    TheStringList.add( StringToAppend); //add new string at position 'index'
    end
  else //just append
     TheStringList[Index] :=  TheStringList[Index] + ',' + StringToAppend
  end;
end;

Solution

  • There is no built-in function to ensure a TStrings/TStringList has a minimum number of strings. So yes, you will have to add strings manually one at a time.

    I would suggest something more like this:

    procedure AppendToStringListItem(TheStringList: TStrings;
                                     Index : integer;
                                     StringToAppend : string);
    var
      s: string;
    begin
      if Index < 0 then Exit;
      TheStringList.BeginUpdate;
      try
        while Index >= TheStringList.Count do begin
          TheStringList.Append('');
        end;
        s := TheStringList[Index];
        if s = '' then 
          s := StringToAppend
        else
          s := s + ',' + StringToAppend;
        TheStringList[Index] := s;
      finally
        TheStringList.EndUpdate;
      end;
    end;
    

    However, this does require you to know the desired index ahead of time, which means searching the TStringList beforehand, eg:

    function AlreadyExistsInStringListItem(const S, StringToAppend: string): Boolean;
    begin
      Result := ...;
    end;
    
    function FindIndexToAppendToStringListItem(TheStringList: TStrings;
                                               StringToAppend : string);
    begin
      for Result := 0 to TheStringList.Count-1 do
      begin
        if not AlreadyExistsInStringListItem(TheStringList[Result], StringToAppend) then
          Exit;
      end;
      Result := TheStringList.Count;
    end;
    
    procedure AppendToStringListItem(TheStringList: TStrings;
                                     Index : integer;
                                     StringToAppend : string);
    var
      s: string;
    begin
      if Index < 0 then Exit;
      TheStringList.BeginUpdate;
      try
        while Index >= TheStringList.Count do begin
          TheStringList.Append('');
        end;
        s := TheStringList[Index];
        if s = '' then 
          s := StringToAppend
        else
          s := s + ',' + StringToAppend;
        TheStringList[Index] := s;
      finally
        TheStringList.EndUpdate;
      end;
    end;
    
    Index := FindIndexToAppendToStringListItem(TheStringList, 'a.co.uk');
    AppendToStringListItem(TheStringList, Index, 'a.co.uk');
    

    Depending on your code's design, that could be wasted overhead. You could simplify that logic by merging the searching and inserting together, eg:

    function AlreadyExistsInStringListItem(const S, StringToAppend: string): Boolean;
    begin
      Result := ...;
    end;
    
    procedure AppendToStringListItem(TheStringList: TStrings;
                                     StringToAppend : string);
    var
      i : integer;
      s: string;
    begin
      TheStringList.BeginUpdate;
      try
        for i := 0 to TheStringList.Count-1 do
        begin
          s := TheStringList[i];
          if not AlreadyExistsInStringListItem(s, StringToAppend) then
          begin
            TheStringList[i] := s + ',' + StringToAppend;
            Exit;
          end;
        end;
        TheStringList.Append(StringToAppend);
      finally
        TheStringList.EndUpdate;
      end;
    end;
    
    AppendToStringListItem(TheStringList, 'a.co.uk');