Adding a single element to a dynamic array

This is a very frequent pattern in all of my code:

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

Is there no way to do this on one line?

Edit: This is incredibly inefficient. I know. I use dynamic arrays (in my own code, in my personal projects that I only use), because they are the easiest to use, and I just need to do everything with a minimal amount of code.

+6
source share
5 answers

Here's a generic hack that 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; 

Using:

 var TestArray: TArray<Integer>; begin TAppender<Integer>.Append(TestArray, 5); end. 
+15
source

Each time you call SetLength , memory is reallocated. Perhaps the whole array needs to be copied to another location. And you who just wanted to add one element to the array!

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

 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 practical example of such an approach.

If you donโ€™t know any upper bound a priori, select it in large pieces:

 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; 

Here is a practical example of such an approach.

+9
source

This is an anti-pattern that leads to memory fragmentation. Instead, use Generics.Collections.TList<T> and call the Add method to add new elements.

There is not a single liner to expand the array and add an element. You can create your own dynamic array wrapper using generics to do this if you want. Essentially that Generics.Collections.TList<T> .

+4
source

If you have Delphi 2009 or later, and you really want to cut this piece of code, you can 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; 
+2
source
 MyList.Add(myobject); 

IMO Dynamic arrays should only be used when, at compile time, you do not know the exact size of the array, but at run time, which you will know.

If you need to constantly manipulate the size of your array, you should not use the array, but TList or one of its descendants, as others have mentioned: TObjectList, TInterfaceList, TStringList.Objects [] can all be used (and abused), and there are also some new ones , and TList is for primitive types. TList used to be a bit of a pain before generics were introduced in Delphi - you had to work with pointers, but with generics: TList <T> is very easy.

In addition, use the bandwidth property of any list you create - it will pre-allocate a given amount of memory so that your code does not call up a large amount of memory, to juggle it every time you perform an operation on your list. (If you go beyond the allocated capacity, the memory manager will give you more memory at runtime - you wonโ€™t work - see Delphi Help)

+2
source

Source: https://habr.com/ru/post/886476/


All Articles