How to concatenate array of string elements into a string
Since you are using Delphi 2007 you have to do it you self:
function StrArrayJoin(const StringArray : array of string; const Separator : string) : string;
var
i : Integer;
begin
Result := '';
for i := low(StringArray) to high(StringArray) do
Result := Result + StringArray[i] + Separator;
Delete(Result, Length(Result), 1);
end;
Simply traverse the array and concat it with your seperator.
And a small test example:
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption :=StrArrayJoin(['This', 'is', 'a', 'test'], ' ');
end;
The accepted answer is not ideal in terms of speed, especially if multiple threads are used. This approach is 3x faster on single core, and scales well on SMP.
function JoinStrings(const s: array of string; Delimiter: Char): string;
var
i, c: Integer;
p: PChar;
begin
c := 0;
for i := 0 to High(s) do
Inc(c, Length(s[i]));
SetLength(Result, c + High(s));
p := PChar(Result);
for i := 0 to High(s) do begin
if i > 0 then begin
p^ := Delimiter;
Inc(p);
end;
Move(PChar(s[i])^, p^, SizeOf(Char)*Length(s[i]));
Inc(p, Length(s[i]));
end;
end;
Speed test:
program Project1;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils, StrUtils, Classes;
function StrArrayJoin(const StringArray: array of string; const Separator: string) : string;
var
i : Integer;
begin
Result := '';
for i := low(StringArray) to high(StringArray) do
Result := Result + StringArray[i] + Separator;
Delete(Result, Length(Result), 1);
end;
function JoinStrings(const s: array of string; Delimiter: Char): string;
var
i, c: Integer;
p: PChar;
begin
c := 0;
for i := 0 to High(s) do
Inc(c, Length(s[i]));
SetLength(Result, c + High(s));
p := PChar(Result);
for i := 0 to High(s) do begin
if i > 0 then begin
p^ := Delimiter;
Inc(p);
end;
Move(PChar(s[i])^, p^, SizeOf(Char)*Length(s[i]));
Inc(p, Length(s[i]));
end;
end;
var
TestData: array of string;
type
TTestThread = class(TThread)
protected
Func: Boolean;
Count: Integer;
procedure Execute; override;
end;
procedure TTestThread.Execute;
var
dtStart: TDateTime;
i: Integer;
begin
dtStart := Now;
Count := 0;
repeat
for i := 1 to 1000 do
if Func then
JoinStrings(TestData, ';')
else
StrArrayJoin(TestData, ';');
InterlockedIncrement(Count);
until Now > dtStart + 1/86400;
end;
procedure TestSmp(CpuCount: Integer; Func: Boolean);
var
i, c: Integer;
Threads: array of TTestThread;
begin
SetLength(Threads, CpuCount);
for i := 0 to High(Threads) do begin
Threads[i] := TTestThread.Create(true);
Threads[i].Func := Func;
Threads[i].Resume;
end;
c := 0;
for i := 0 to High(Threads) do begin
Threads[i].WaitFor;
Inc(c, Threads[i].Count);
Threads[i].Free;
end;
WriteLn(c);
end;
procedure Init();
var
i: Integer;
begin
SetLength(TestData, 1000);
for i := 0 to High(TestData) do
TestData[i] := DupeString('x', Random(32));
end;
begin
try
Init();
Assert(StrArrayJoin(TestData, ';') = JoinStrings(TestData, ';'));
TestSmp(1, false);
TestSmp(1, true);
TestSmp(4, false);
TestSmp(4, true);
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
Readln;
end.
Results: on a quad-core CPU JoinStrings is 12x faster.
StrArrayJoin 1 thread: 55
JoinStrings 1 thread: 184
StrArrayJoin 4 threads: 58
JoinStrings 4 threads: 713
In delphi for .NET you can use the framework Join function , while if you don't want to rely on the .NET framework then you can link the open source JCL library : take a look at the IJclStringList interface of the library .
JclStringList.Join(',');
Otherwise as someone suggested in comments you can simply use a TStringList this way :
arrayList.Delimiter := ',';
arrayList.QuoteChar := '';
joinedArray := arrayList.DelimitedText;
Note that latest version of Delphi XEs(since XE3 if I well remember) have a TStringHelper class that adds the Join method to the String class :
class function Join(const Separator: string; const Values:
IEnumerator<string>): string; overload; static;