如何在 Delphi 中将一个数组附加到另一个相同类型的数组?
How to append one array to another array of same type in Delphi?
如何在 Delphi 中不使用迭代语句(for
或 while
循环)将一个数组附加到另一个相同类型的数组?
有两个 dynamic arrays arr1
和 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;
您可以像这样将第一个附加到第二个:
SetLength(arr2, Length(arr2) + Length(arr1));
Move(arr1[0], arr2[3], Length(arr1) * SizeOf(Integer));
参见System.Move。
正如 指出的那样,您可以对托管类型执行以下操作:
SetLength(arr2, Length(arr2) + Length(arr1));
for i := Low(arr1) to High(arr1) do
arr2[3+i] := arr1[i];
在最近的 Delphi 版本 (XE7+) 中,您可以只使用 +
运算符或 Concat
例程来附加数组。 Link. Official help(没有提到 +
)
否则请编写您自己的过程(如果可能,请使用通用数组)。快速示例(在 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;
用法:
var
A, B: TArray<String>;
begin
A := TArray<String>.Create('1', '2', '3');
B := TArray<String>.Create('4', '5');
TArrHelper.AppendArrays<String>(A, B);
如果您不介意您的原始数组被破坏,那么有一个骇人听闻的解决方案。它可能比循环快很多,因为循环的每次迭代都必须添加一个引用,而 DestructiveConcatArrays
保留引用计数。
这意味着不允许复制 个要移动 的字符串。它们要么在 Destination
中,要么在 Source
中,但不能同时在两者中。否则他们的引用计数无论如何都必须更新——在一个循环中。
备注
在 Move
和 FillChar
之间,所有复制过来的字符串引用都没有正确地重新计数。但是在 FillChar
之后,他们又来了。必须注意,在不稳定状态下,没有任何线程可以访问 Source
数组。
换句话说:以下不需要 RTL 添加或删除引用,但它很棘手并且会破坏原始(第二个)数组:
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;
小心!
以上不是通用的解决方案。这是一个 hack,专为这个单一目的而设计。但它按预期工作。我对此进行了测试。 但它不是线程安全的,尽管它可能是线程安全的。
更新
这正是 C++ 为 rvalue 表达式引入的 移动语义 。只需将 Source
视为 rvalue.
如何在 Delphi 中不使用迭代语句(for
或 while
循环)将一个数组附加到另一个相同类型的数组?
有两个 dynamic arrays arr1
和 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;
您可以像这样将第一个附加到第二个:
SetLength(arr2, Length(arr2) + Length(arr1));
Move(arr1[0], arr2[3], Length(arr1) * SizeOf(Integer));
参见System.Move。
正如
SetLength(arr2, Length(arr2) + Length(arr1));
for i := Low(arr1) to High(arr1) do
arr2[3+i] := arr1[i];
在最近的 Delphi 版本 (XE7+) 中,您可以只使用 +
运算符或 Concat
例程来附加数组。 Link. Official help(没有提到 +
)
否则请编写您自己的过程(如果可能,请使用通用数组)。快速示例(在 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;
用法:
var
A, B: TArray<String>;
begin
A := TArray<String>.Create('1', '2', '3');
B := TArray<String>.Create('4', '5');
TArrHelper.AppendArrays<String>(A, B);
如果您不介意您的原始数组被破坏,那么有一个骇人听闻的解决方案。它可能比循环快很多,因为循环的每次迭代都必须添加一个引用,而 DestructiveConcatArrays
保留引用计数。
这意味着不允许复制 个要移动 的字符串。它们要么在 Destination
中,要么在 Source
中,但不能同时在两者中。否则他们的引用计数无论如何都必须更新——在一个循环中。
备注
在 Move
和 FillChar
之间,所有复制过来的字符串引用都没有正确地重新计数。但是在 FillChar
之后,他们又来了。必须注意,在不稳定状态下,没有任何线程可以访问 Source
数组。
换句话说:以下不需要 RTL 添加或删除引用,但它很棘手并且会破坏原始(第二个)数组:
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;
小心!
以上不是通用的解决方案。这是一个 hack,专为这个单一目的而设计。但它按预期工作。我对此进行了测试。 但它不是线程安全的,尽管它可能是线程安全的。
更新
这正是 C++ 为 rvalue 表达式引入的 移动语义 。只需将 Source
视为 rvalue.