Is there any simple univesal way to add 2 arrays into one? In the case below it is not possible simply use C := A + B
statement...
I would like to avoid making algorhytm for it everytime .
TPerson = record
Birthday: Tdate;
Name, Surname:string;
end;
Tpeople = array of TPerson;
var A, B, C:Tpeople;
C:=A+B; // it is not possible
thanx
Due to the two string
fields in each TPerson
record, you can't just use binary "move", since you'll mess the reference counting of string
- especially in a multi-threaded environment.
You can do it manually - this is fast and nice:
TPerson = record
Birthday: TDate;
Name, Surname: string;
end;
TPeople = array of TPerson;
var A, B, C: TPeople;
// do C:=A+B
procedure Sum(const A,B: TPeople; var C: TPeople);
begin
var i, nA,nB: integer;
begin
nA := length(A);
nB := length(B);
SetLength(C,nA+nB);
for i := 0 to nA-1 do
C[i] := A[i];
for i := 0 to nB-1 do
C[i+nA] := B[i];
end;
Or you can use our TDynArray
wrapper, which has a method for handling such cases:
procedure AddToArray(var A: TPeople; const B: TPeople);
var DA: TDynArray;
begin
DA.Init(TypeInfo(TPeople),A);
DA.AddArray(B); // A := A+B
end;
The AddArray
method can add a sub-port of the original array:
/// add elements from a given dynamic array
// - the supplied source DynArray MUST be of the same exact type as the
// current used for this TDynArray
// - you can specify the start index and the number of items to take from
// the source dynamic array (leave as -1 to add till the end)
procedure AddArray(const DynArray; aStartIndex: integer=0; aCount: integer=-1);
Note that with such records, it will use the System._CopyRecord
RTL function, which is not so optimized for speed. I've written a faster version - see this blog article or this forum thread.
If you use dynamic arrays in functions/procedures, don't forget to use explicitly const
or var
parameters (as I coded above), otherwise it will make a temporary copy at each call, therefore it may be slow.
There is nothing built in that allows dynamic arrays to be concatenated.
You may consider using one of the generic container classes found in Generics.Collections, TList.
In your case you would have 3 instances of TList, say A, B and C. Then you could write
A.Clear;
A.AddRange(B);
A.AddRange(C);
I think this is as close as you can get to what you want with what is delivered out of the box.
If you are prepared to do a bit of coding yourself then you could make use of operator overloading to use the exact syntax you requires. Declare a record containing an array of TPerson with private visibility. You then need to implement an Add operator, a Count property and a default Items[] property. This could be made generic too so you only need write it once.
TTurboArray = record<T>
private
FItems: array of T;
//property accessors here
public
class operator Add(a, b: TTurboArray<T>): TTurboArray<T>;
property Count: Integer read GetCount write SetCount;
property Items[Index: Integer]: T read GetItem write SetItem; default;
end;
This idea can be extended into a very powerful data structure as you see fit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With