How to append one array to another array of same type in Delphi?

一个人想着一个人 提交于 2019-12-20 04:57:11

问题


How to append one array to another array of the same type without using iterative statements (for or while loops) in Delphi?


回答1:


Having two dynamic arrays arr1 and arr2

var
  arr1, arr2: array of Integer;
. . .
SetLength(arr1, 3);
arr1[0] := 1;
arr1[1] := 2;
arr1[2] := 3;

SetLength(arr2, 3);
arr2[0] := 4;
arr2[1] := 5;
arr2[2] := 6;

you can append the first to the second like this:

SetLength(arr2, Length(arr2) + Length(arr1));
Move(arr1[0], arr2[3], Length(arr1) * SizeOf(Integer));

See System.Move.


As Uwe Raabe's comment points out, you can do as follows for managed types:

SetLength(arr2, Length(arr2) + Length(arr1));
for i := Low(arr1) to High(arr1) do
  arr2[3+i] := arr1[i];



回答2:


In the last Delphi versions (XE7+) you can just use + operator or Concat routine to append arrays. Link. Official help (doesn't mention +)

Otherwise write your own procedure (use generic arrays if possible). Quick example (checked in XE3):

type 
TArrHelper = class
  class procedure AppendArrays<T>(var A: TArray<T>; const B: TArray<T>);
end;


class procedure TArrHelper.AppendArrays<T>(var A: TArray<T>;
  const B: TArray<T>);
var
  i, L: Integer;
begin
  L := Length(A);
  SetLength(A, L + Length(B));
  for i := 0 to High(B) do
    A[L + i] := B[i];
end;

usage:

var
  A, B: TArray<String>;
begin
  A := TArray<String>.Create('1', '2', '3');
  B := TArray<String>.Create('4', '5');
  TArrHelper.AppendArrays<String>(A, B);



回答3:


If you don't mind that your original array is destroyed, then there is a hackish solution. It is probably a lot faster than a loop, because each iteration of the loop must add one reference, while DestructiveConcatArrays preserves the reference count.

This means that copies of the strings to be moved are not allowed. They are either in Destination, or in Source, but can't be in both at the same time. Otherwise their refcounts would have to be updated anyway -- in a loop.

Note

Between the Move and the FillChar, all string references copied over are not properly refcounted. But after the FillChar, they are again. Care must be taken that nothing, no thread, should be able to access the Source array in that unstable state.

In other words: the following does not require the RTL to add or remove references, but it is tricky and it destroys the original (second) array:

procedure DestructiveConcatArrays(var Destination, Source: TArray<string>);
var
  LenD, LenS: Integer;
begin
  LenD := Length(Destination);
  if LenD = 0 then
    Destination := Source
  else
  begin
    LenS := Length(Source);
    if Length(Source) > 0 then
    begin
      SetLength(Destination, LenD + LenS);
      // Copy strings -- Afterwards, the refcounts of all strings copied over are  
      //                 out of sync.
      Move(Source[0], Destination[LenD], LenS * SizeOf(string));
      // Clear Source -- Afterwards, all refcounts are in sync again.
      FillChar(Source[0], LenS * SizeOf(string), 0);
    end;
  end;
  Source := nil;
end;

Careful!

The above is not a general solution. It is a hack, designed for this single purpose only. But it works as expected. I tested that. But it is not thread-safe, although it can probably be made to be.


Update

This is very much what C++ introduced with move semantics for rvalue expressions. Just consider the Source as an rvalue.



来源:https://stackoverflow.com/questions/35406753/how-to-append-one-array-to-another-array-of-same-type-in-delphi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!