带有tlist的Delphi动态数组

时间:2015-02-17 19:45:53

标签: arrays delphi multidimensional-array lazarus tlist

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

DIM num_arr [3,3,3]

我想创建一个double的三维数组,每个索引从0到2变化。

到目前为止,我只有创建“TList数组”的功能。我使用两个TList对象来保存数组维度和数据项列表,我有第三个保存存储/检索数据的索引。我无法想象的是如何将索引列表与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;

2 个答案:

答案 0 :(得分:3)

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

假设维度保存在动态数组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;

答案 1 :(得分:0)

上述LinearIndex函数对某些不平衡数组不起作用。例如,如果我正确地分配“dim”来保存值[2,3],则该函数将返回2作为“idx”的两个内容的索引:[0,2],[1,0]。 我在StackOverflow上创建了一个基于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;