将一个元素附加到动态数组

Vla*_*eev 12 delphi

这是我的代码中非常频繁的模式:

SetLength(SomeDynamicArray, Length(SomeDynamicArray)+1);
SomeDynamicArray[High(SomeDynamicArray)] := NewElement;
Run Code Online (Sandbox Code Playgroud)

有没有办法在一行中做到这一点?

编辑:这非常低效.我知道.我使用动态数组(在我自己的代码中,在我个人的项目中,我只使用),因为它们最容易使用,我只需要用尽可能少的代码完成工作.

Vla*_*eev 20

这是一个泛型的破解,只适用于TArray<T>:

type
  TAppender<T> = class
    class procedure Append(var Arr: TArray<T>; Value: T);
  end;

class procedure TAppender<T>.Append;
begin
  SetLength(Arr, Length(Arr)+1);
  Arr[High(Arr)] := Value;
end;
Run Code Online (Sandbox Code Playgroud)

用法:

var
  TestArray: TArray<Integer>;

begin
  TAppender<Integer>.Append(TestArray, 5);
end.
Run Code Online (Sandbox Code Playgroud)


And*_*and 12

每次调用SetLength内存都会重新分配.也许整个阵列需要复制到不同的位置.而你只想在阵列中添加一个元素!

基本上:永远不要这样做.它有两种方法.最简单的情况是,如果您事先知道数组的最大大小:

procedure Example1;
var
  data: array of string;
  ActualLength: integer;

  procedure AddElement(const Str: string);
  begin
    data[ActualLength] := Str;
    inc(ActualLength);
  end;

begin

  ActualLength := 0;
  SetLength(data, KNOWN_UPPER_BOUND);

  for ...
    while ...
      repeat ...
        AddElement(SomeString);

  SetLength(data, ActualLength);

end;
Run Code Online (Sandbox Code Playgroud)

是这种方法的一个实际例子.

如果你不知道任何上限先验的,然后分配大块:

procedure Example2;
const
  ALLOC_BY = 1024;
var
  data: array of string;
  ActualLength: integer;

  procedure AddElement(const Str: string);
  begin
    if ActualLength = length(data) then
      SetLength(data, length(data) + ALLOC_BY);

    data[ActualLength] := Str;
    inc(ActualLength);
  end;

begin

  ActualLength := 0;
  SetLength(data, ALLOC_BY);

  for ...
    while ...
      repeat ...
        AddElement(SomeString);

  SetLength(data, ActualLength);

end;
Run Code Online (Sandbox Code Playgroud)

第二种方法是在运行时库的实现TList<T>,TObjectList<T>,TStringList等.因此,当您使用这些类,它是完全正常的列表中选择一个项目在一个时间追加.

  • 我发现这篇文章没有用(并拒绝了它),因为:1)它没有回答上述问题 2)它告诉我一些我已经知道的事情 3)建议的解决方案与我需要的方向截然相反(代码简单和简洁)4)它命令读者总是[不]做某事,这并不适用于所有情况(例如我的)。 (3认同)
  • 根据我自己的经验,我将 ALLOC_BY 设置为实际长度的 125%。它类似于“TList”增长步骤。 (2认同)

Bri*_*ian 6

从Delphi XE7开始,您可以执行以下操作:

SomeDynamicArray := SomeDynamicArray + [NewElement];
Run Code Online (Sandbox Code Playgroud)

参考资料:Marco Tech Blog,2014年9月18日:Delphi XE7中的动态阵列

  • 这个方法会重新分配内存吗? (2认同)
  • @Doege 对于语言参考,Marco Cantu 编写的《Object Pascal 手册》目前可以从 Embarcadero 免费下载,非常可靠。 (2认同)

Dav*_*nan 5

这是导致内存碎片的反模式。而是使用Generics.Collections.TList<T>并调用Add方法来添加新项目。

没有一个衬板可以扩展阵列并添加项目。您可以根据需要使用泛型创建自己的动态数组包装器。本质上Generics.Collections.TList<T>就是这样。


Tor*_*ins 5

有一个方便的插入过程,您可以像这样使用:

Insert([NewElement], SomeDynamicArray, High(SomeDynamicArray));
Run Code Online (Sandbox Code Playgroud)