我正在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;
答案 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;