delphi 向动态数组追加一个元素

dsf9zpds  于 2023-03-01  发布在  其他
关注(0)|答案(8)|浏览(289)

将一个元素追加到动态数组的直接方法如下:

SetLength(SomeDynamicArray, Length(SomeDynamicArray) + 1);
SomeDynamicArray[High(SomeDynamicArray)] := NewElement;

不管内存碎片导致的性能问题,是否有办法在一行中完成此操作?

juzqafwq

juzqafwq1#

从 Delphi XE7开始,您可以:

SomeDynamicArray := SomeDynamicArray + [NewElement];

参考:马可科技博客,2014年9月18日:Dynamic Arrays in Delphi XE7

j8yoct9x

j8yoct9x2#

这里有一个泛型的黑客只适用于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;

用法:

var
  TestArray: TArray<Integer>;

begin
  TAppender<Integer>.Append(TestArray, 5);
end.
ep6jt1vc

ep6jt1vc3#

每次你调用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;

下面是这种方法的一个实际例子。
如果你不知道任何上限 * 先验 *,然后分配大块:

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;

第二种方法是在运行库的TList<T>TObjectList<T>TStringList等中实现的。因此,当您使用这些类时,一次向列表添加一个项是非常好的。

2vuwiymt

2vuwiymt4#

这是导致内存碎片的反模式,而是使用Generics.Collections.TList<T>并调用Add方法来添加新项。
没有一个程序可以扩展一个数组并添加一个项。如果你愿意,你可以使用泛型创建你自己的动态数组 Package 器来完成这件事。本质上这就是Generics.Collections.TList<T>

carvr3hs

carvr3hs5#

有方便的插入程序,你可以这样使用:

Insert([NewElement], SomeDynamicArray, High(SomeDynamicArray));
kg7wmglp

kg7wmglp6#

MyList.Add(myobject);

IMO动态数组应该只在编译时不知道数组的确切大小但在运行时知道的情况下使用。
如果你需要不断地控制数组的大小,你不应该使用数组,而应该使用TList或者它的后代,就像其他人提到的那样:TObjectList,TInterfaceList,TStringList.Objects[]都可以被使用(和滥用),也有一些新的对象,TList用于原语类型。在泛型被引入 Delphi 之前,TList曾经是一件痛苦的事情--你必须使用指针--但是使用泛型:TList非常简单。
另外,使用你创建的任何列表的capacity属性--它会预先分配给定量的内存,这样你的代码就不会在你每次对列表执行操作时造成大量内存的浪费。(如果你超出了你分配的容量,内存管理器会在运行时给你更多的内存--你不会失败的--参见 Delphi 帮助)

zc0qhyus

zc0qhyus7#

如果您使用的是 Delphi 或更高版本,并且确实希望缩短上述代码段,则可以尝试类似下面的方法

type
  DataArray<T> = record
    Data: array of T;
    procedure Append(const Value: T);
    function Count: integer;
  end;

{ DataArray<T> }

procedure DataArray<T>.Append(const Value: T);
begin
  SetLength(Data, length(Data) + 1);
  Data[high(Data)] := Value;
end;

function DataArray<T>.Count: integer;
begin
  result := length(Data);
end;

那你就可以

procedure TForm1.FormCreate(Sender: TObject);
var
  data: DataArray<string>;
begin
  data.Append('Alpha');
  data.Append('Beta');
  Caption := IntToStr(data.Count) + ': ' data.Data[0] + ' & ' + data.Data[1];
end;
t5fffqht

t5fffqht8#

您可以简单地使用这段代码将一个元素附加到任何动态数组的末尾。

...
var
  myArray: array of Integer;
  element: Integer;
...
Insert(element, myArray, MaxInt);
...

相关问题