如何重构数组之间的复制/移动数据?

时间:2015-12-26 18:49:03

标签: arrays delphi delphi-xe7

我有一个进程将数据读入150多个临时数组,处理数据并从临时数组复制到工作数组中。工作数组在一个全局数组中,因此我可以导入多个数据,这意味着我可以重复相同的过程多达100次,最后得到一个大数组,其中包含我可以使用的100x工作数据,比较和执行操作。 / p>

我有150多个阵列,所以150次:

    // for each array
    SetLength(myData[Idx].WorkNames,Length(tmpNames)); // <- prepare to copy
    for i := 0 to High(tmpNames) do  // <- copy
      myData[Idx].WorkNames[i]:=tmpNames[i];
    SetLength(tmpNames,0);  //  <- clear tmp array

每个阵列有4行代码 - 150x4 = 600 loc +初始+空行 - 大约900 loc

这是我做的例子:

type

  TName = record
    NameID:integer;
    Description:string;
  end;

  TItem = record
    ItemID:integer;
    Description:string;
    Active:boolean;
  end;

  TWorkData = record
      WorkDataType:string;
      WorkNames:array of TName;
      WorkItems:array of TItem;
    end;

var

  AllWorkData:array of TWorkData;  //  <- global array that has all work data - up to 100x sets of work data
  tmpNames:array of TName; // <- tmp arrays before saving to work array
  tmpItems:array of TItem; // 

procedure TForm1.Button1Click(Sender: TObject);
var i,Idx:integer;
begin

  // 1. read data into tmp arrays
  ReadDataIntoTmpArrays;
  ProcessTmpData;

  // 2. copy tmp arrays into work data
  Idx:=GetWorkDataIdx; // <- work data sequence number; start with 0
  AllWorkData[Idx].WorkDataType:=GetWorkDataName(Idx);
  SetLength(AllWorkData[Idx].WorkNames,Length(tmpNames));
  SetLength(AllWorkData[Idx].WorkItems,Length(tmpItems));

  for i := 0 to High(tmpNames) do
    AllWorkData[Idx].WorkNames[i]:=tmpNames[i];

  for i := 0 to High(tmpItems) do
    AllWorkData[Idx].WorkItems[i]:=tmpItems[i];

  // 3. clear tmp arrays
  SetLength(tmpNames,0);
  SetLength(tmpItems,0);

end;

问题:我能做些什么更容易维护,重构代码?

1 个答案:

答案 0 :(得分:1)

如果你真的想要复制,那么使用泛型来做。您可以从TArray中声明的System.Generics.Collections类静态类方法派生。例如:

type
  TArray = class(Generics.Collections.TArray)
  public
    class function Copy<T>(const Source: array of T; Index, Count: Integer): TArray<T>; overload; static;
    class function Copy<T>(const Source: array of T): TArray<T>; overload; static;
  end;

....

class function TArray.Copy<T>(const Source: array of T; Index, Count: Integer): TArray<T>;
var
  i: Integer;
begin
  SetLength(Result, Count);
  for i := 0 to high(Result) do begin
    Result[i] := Source[i+Index];
  end;
end;

class function TArray.Copy<T>(const Source: array of T): TArray<T>;
var
  i: Integer;
begin
  SetLength(Result, Length(Source));
  for i := 0 to high(Result) do begin
    Result[i] := Source[i];
  end;
end;

请注意,上述所有内容都要求您停止使用array of TMyType,而是开始使用通用动态数组TArray<TMyType>

在你的情况下,虽然你过于复杂。替换:

SetLength(myData[Idx].WorkNames,Length(tmpNames)); // <- prepare to copy
for i := 0 to High(tmpNames) do  // <- copy
  myData[Idx].WorkNames[i]:=tmpNames[i];
SetLength(tmpNames,0);  //  <- clear tmp array

使用:

myData[Idx].WorkNames := tmpNames;
tmpNames := nil;

如果您准备让tmpNames只留下范围,那么您可以使用一行:

myData[Idx].WorkNames := tmpNames;

尽管如果tmpNames被重新用于其他数组,则需要nil分配。

然后,就我在问题中的代码中所看到的,你根本不需要临时数组。为什么不直接在长寿命数据结构上运行。

仅当赋值的源和目标与赋值兼容时,才允许这些数组赋值。您的类型不是因为您使用了不同类型。切换到TArray<T>以避免这种情况。有关详情,请参阅此问题:Why are two seemingly identical dynamic array types deemed not assignment compatible?

请记住,动态数组是引用类型。在此处显示的用法中,您需要做的就是复制引用。您只需要一个实际数组的实例。因此根本不需要复制。