Скопировать динамический массив из списка в блок - PullRequest
3 голосов
/ 23 февраля 2012

в посте: Копировать подсписок из списка остался, объяснили мне, что для копирования подсписка в списке нужно скопировать отдельные элементы следующим образом:

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

Я проверил, что этот метод копирования для элементов, намного более высоких в списке, занимает много времени, в том числе и для некоторых минералов. Пытаясь смоделировать статический массив в том же состоянии, я беру несколько миллисекунд, копируя все подсписки в массиве за один раз, а не для одного элемента. Просто для лучшего объяснения, у меня есть:

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.

Так что я решил использовать не список в качестве подсписка, а массив и так далее, но в моем случае я вообще не знаю, сколько элементов в массиве, и для этого нужен динамический массив. Я изменил код в:

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.

и так, у меня снова проблема раньше; конечно, меняя эту строку:

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

в режиме копирования один элемент, все работает. Теперь я спрашиваю, если действительно невозможно скопировать массив за раз, не делайте копию для отдельных элементов, мне это нужно только для вопроса о скорости. И время очень важно. Еще раз большое спасибо всем, кто может решить эту проблему. Еще раз спасибо.

Ответы [ 2 ]

3 голосов
/ 23 февраля 2012

Вам необходимо добавить копию массива.В противном случае, поскольку вы продолжаете устанавливать длину переменной массива в одно и то же значение, вы в конечном итоге работаете с одним и тем же динамическим массивом.Чтобы сделать копию массива, просто позвоните Copy, прежде чем добавить его в свой список:

MyList.Add(Copy(MyArray));
2 голосов
/ 23 февраля 2012

если я вас правильно понимаю, вы хотите скопировать память для повышения скорости, вот один из способов сделать это:

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;
...