2015-12-26 35 views
1

我有一个进程将数据读入150多个临时数组,处理数据并从临时数组复制到工作数组中。工作阵列在一个全局数组中,因此我可以导入多个数据,这意味着我可以重复同一个过程多达100次,最后使用大数组中的一组数据来保存我可以使用,比较和执行的100倍工作数据。如何重构数组之间的复制/移动数据?

我有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

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

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?

请记住,动态数组是引用类型。在这里显示的用法中,您只需复制参考。您只需要实际阵列的一个实例。所以根本不需要复制。

+0

这行'AllWorkData [0] .WorkNames:= tmpNames;'说:'[dcc32错误] Unit1.pas(90):E2008 Incompatible types'。我究竟做错了什么? –

+0

这是因为.'WorkNames'和'tmpNames'是不属于赋值兼容的不同类型。改用'TArray '代替'T'的适当类型。 –

+0

啊哈,现在有用。所以,你建议用'TArray '替换所有'T'阵列...... –

相关问题