Delphi 带有 tlist 的动态数组

Delphi dynamic array with tlist

我正在 Delphi/Lazarus 中为类似于 BASIC 的语言创建一个简单的解释器。 我已经实现了很多功能。此时此刻,我正在尝试创建一个类似 DIM 的命令来处理多维数值数组。 我的想法是使用 TList 模拟仅受可用内存限制的多维数组。例如,当在我的解释器中声明如下命令时:

昏暗 num_arr[3,3,3]

我想创建一个双精度的三维数组,每个索引从 0 到 2 不等。

到目前为止,我只有创建 "TList array" 的功能。我使用两个 TList 对象来保存数组维度和数据项列表,我有第三个对象保存 store/retrieve 数据的索引。我想不通的是如何将索引列表关联到 TList 中的特定条目。当数组达到二维时很简单,我可以将每对索引转换为数字序列,但对三维和更多维度没有成功。 有什么算法可以用来解决这个问题吗?真的很难找到与那件事相关的东西。 欢迎任何有关如何实施类似内容的建议。下面我发布了到目前为止我开发的部分代码:

//Creates a "n" dimensional array
function array_allocate(Dim: TList; var DataArray: TList): integer;
var
  i: integer;
  s: string;
begin
  Result := 1;
  //Simple way to find the array length
  //For example. An array with dimensions [3,3,3] will handle 27 items
  for i := 0 to Dim.Count-1 do
  begin
    Result := Result * Integer(Dim[i]);
  end;
  Result := Result;
  DataArray.Capacity := Result; //DataArray now handles 27 items

  //************************************
  //Every line below is just for testing
  //************************************
  fmMain.Memo1.Lines.Add('Allocating size for array with '+IntToStr(Dim.Count)+' dimension(s).');
  s := '';
  for i := 0 to Dim.Count-1 do
    s := s + '['+IntToStr(Integer(Dim[i]))+']';
  fmMain.Memo1.Lines.Add('DIM Sizes: '+s);
  fmMain.Memo1.Lines.Add('Manage: '+IntToStr(Result)+' Items.');
end;

{*************************************}
{NOT functional, this is the challenge}
{*************************************}
function calculate_offset(Dim, Indexes: TList; var DataArray: TList; BaseAddr: integer): integer;
var
  i, Depth, dimIdx: Integer;
  k,index,sizeProduct: integer;
begin
  for Depth := 0 to Dim.Count-1 do
    for dimIdx := 0 to Integer(Dim[Depth])-1 do
      fmMain.mmOut.Lines.Add('Dim: '+IntToStr(Depth)+' ,Index: '+IntToStr(dimIdx));

  result := 0;
end;

procedure TfmMain.FormShow(Sender: TObject);
var
  dataList: TList; //keep the data
  dimList: TList; //keep the dimensions
  indexList: TList; //keep the indexes
  offset: integer;
begin
  dimList := TList.Create; //create the dim array
  //simulate the creation of an array with dimension [3,3,3]
  //something like DIM myVar[3,3,3]
  dimList.Add(Pointer(3));
  dimList.Add(Pointer(3));
  dimList.Add(Pointer(3));

  dataList := TList.Create; //create the data list
  array_allocate(dimList, dataList); //allocates memory

  //indexList is the way to indicate which index to retrieve/store data
  indexList := TList.Create;
  indexList.Add(Pointer(1));
  indexList.Add(Pointer(1));
  indexList.Add(Pointer(1));
  indexList.Add(Pointer(1));

  //The idea is to relate indexes like [0,0,0], [0,0,1], [0,1,1] to
  //a numeric sequence between 0 to 26 in this case (DIM = [3,3,3])
  offset := calculate_offset(dimList, indexList, dataList, 1, 0);

  indexList.Free;
  dimList.Free;
  dataList.Free;
end;

当我读到你的问题时,你想从一个索引元组转换为一个线性索引,假设行主要存储。

假设维度保存在动态数组 dim 中,索引保存在动态数组 idx 中。那么线性指数是这样计算的:

function LinearIndex(const dim, idx: array of Integer): Integer;
var 
  i: Integer;
begin
  Assert(Length(dim)=Length(idx));
  Assert(Length(dim)>0);
  Result := idx[0];
  for i := 1 to high(dim) do
    Result := Result*dim[i-1] + idx[i];
end;

上述 LinearIndex 函数不适用于某些不平衡数组。例如,如果我正确地分配 "dim" 来保存值 [2,3],该函数将 return 2 作为 "idx" 的两个内容的索引:[0,2], [1,0]。 我根据我在 Whosebug 上找到的 another post 创建了一个 Pascal 函数,这个函数似乎有效。

function LinearIndex2(const dim, idx: array of Integer): Integer;
var
  i,index,mult: Integer;
begin
  Assert(Length(dim)=Length(idx));
  Assert(Length(dim)>0);

  index := 0; mult := 1;
  for i := 0 to High(dim) do
  begin
    index := index + idx[i] * mult;
    mult := mult * dim[i];
  end;

  result := index;
end;