Appending one element to a dynamic array

前端 未结 8 2200
太阳男子
太阳男子 2020-12-05 05:16

This is a very frequent pattern throughout my code:

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


        
相关标签:
8条回答
  • 2020-12-05 06:00

    Here's a hack with generics which only works with 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;
    

    Usage:

    var
      TestArray: TArray<Integer>;
    
    begin
      TAppender<Integer>.Append(TestArray, 5);
    end.
    
    0 讨论(0)
  • 2020-12-05 06:01

    There is handy Insert procedure, that you can use like this:

    Insert([NewElement], SomeDynamicArray, High(SomeDynamicArray));
    
    0 讨论(0)
  • 2020-12-05 06:06

    If you have Delphi 2009 or later, and you really want to shorten the above piece of code, you could try something like

    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;
    

    Then you can do

    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;
    
    0 讨论(0)
  • 2020-12-05 06:08

    Every time you call SetLength the memory gets reallocated. Maybe the entire array needs to be copied to a different location. And you who just wanted to add a single element to the array!

    Basically: never do this. There are two ways out of it. The simplest case is if you beforehand know the maximum size of the array:

    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;
    

    Here is a practial example of this approach.

    If you don't know any upper bound a priori, then allocate in large chunks:

    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;
    

    This second approach is implemented in the run-time library's TList<T>, TObjectList<T>, TStringList etc. Hence, when you use these classes, it is perfectly fine to append the list one item at a time.

    0 讨论(0)
  • 2020-12-05 06:10

    You can simply use this code to append an element to end of any dynamic array. fast and short.

    ...
    var
      myArray: array of Integer;
      element: Integer;
    ...
    Insert(element, myArray, MaxInt);
    ...
    
    0 讨论(0)
  • 2020-12-05 06:12

    Starting with Delphi XE7 you can do:

    SomeDynamicArray := SomeDynamicArray + [NewElement];
    

    ref: Marco Tech Blog, September 18, 2014 : Dynamic Arrays in Delphi XE7

    0 讨论(0)
提交回复
热议问题