Marcello Impastato
Marcello Impastato

Reputation: 2281

Copy dynamic array from list in block

in post: Copy sublist from list was stayed explained me that for copy a sublist in a list need copy single elements doing so:

for iIndex2 := 0 to MyList.Last.Count-1 do 
  MySubList.Add(MyList.Last[iIndex2]); 

I have verified that this method of copy for elements much much highest in list take much time, in order too of some minetes. Trying to simulate with static array in same condition i take few miliseconds, copying all sublist in an array in one time and not for single element. Just for explain better, i have:

program Test_with_array_static;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Generics.Collections;

type
  TMyArray = array [1..10] of Integer;
  TMyList = TList<TMyArray>;

var
  MyArray: TMyArray;
  MyList: TMyList;
  iIndex1, iIndex2: Integer;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }

    MyList := TList<TMyArray>.Create;
    try
      for iIndex1 := 1 to 10 do
      begin
        if MyList.Count <> 0 then MyArray := MyList.Last;
        MyArray[iIndex1] := iIndex1;
        MyList.Add(MyArray);
      end;

      for iIndex1 := 0 to Pred(MyList.Count) do
      begin
        for iIndex2 := 1 to 10 do Write(MyList[iIndex1][iIndex2]:3);
        Writeln;
      end;
    finally
      MyList.Free;
    end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

So i have thinked to use not list as sublist but array and so work, but in my case i don't know in general how much are element in array and need dynamic array for it. I have changed code in:

program Test_with_array_dynamic;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Generics.Collections;

type
  TMyArray = array of Integer;
  TMyList = TList<TMyArray>;

var
  MyArray: TMyArray;
  MyList: TMyList;
  iIndex1, iIndex2: Integer;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }

    MyList := TList<TMyArray>.Create;
    try
      SetLength(MyArray, 10);
      for iIndex1 := 1 to 10 do
      begin
        if MyList.Count <> 0 then MyArray := MyList.Last;
        MyArray[iIndex1] := iIndex1;
        MyList.Add(MyArray);
      end;

      for iIndex1 := 0 to Pred(MyList.Count) do
      begin
        for iIndex2 := 1 to 10 do Write(MyList[iIndex1][iIndex2]:3);
        Writeln;
      end;
    finally
      MyList.Free;
    end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

and so, i have again the problem of before; of course, changing this line:

if MyList.Count <> 0 then MyArray := MyList.Last;

in mode of copy single element, all work. Now i ask, if really not is possible copy an array in a time, without do a copy for single elements, i need it for question of speed only. And time is very much important. Thanks again very much to all that can solve me this problem. Thanks again.

Upvotes: 3

Views: 828

Answers (2)

Rob Kennedy
Rob Kennedy

Reputation: 163347

You need to add a copy of the array. Otherwise, since you keep setting the array variable's length to the same value, you end up working on the same single dynamic array. To make a copy of an array, simply call Copy prior to adding it to your list:

MyList.Add(Copy(MyArray));

Upvotes: 3

user497849
user497849

Reputation:

if I understand you correctly, you want to copy memory to improve speed, here's one way to do it:

type
  TMyArray = array of Integer;

procedure CopyMyArraytest;
var
  LSrcArray: TMyArray;
  LDestArray: TMyArray;
  Index: Integer;
begin
  // set the length, can be later changed
  SetLength(LSrcArray, 100);
  // fill the array
  for Index := Low(LSrcArray) to High(LSrcArray) do
    LSrcArray[index] := index;
  // prepare the length of destination array
  SetLength(LDestArray, Length(LSrcArray));
  // copy elements from source to dest, we need Length(LSrcArray) * SizeOf(Integer)
  // because Move needs the number of bytes, we are using "integer" so a simple
  // multiplication will do the job
  Move(LSrcArray[Low(LSrcArray)], LDestArray[Low(LDestArray)], Length(LSrcArray) * SizeOf(Integer));

  // compare elements, just to make sure everything is good
  for Index := Low(LSrcArray) to High(LSrcArray) do
    if LSrcArray[Index] <> LDestArray[Index] then begin
      ShowMessage('NOOO!!!');
      Exit;
    end;
  ShowMessage('All good');
end;

Upvotes: 2

Related Questions