基本上有两种方法可以解决这个问题
自动表格
自动表使用元表透明地生成子表,基本上在创建它之后您应该能够忘记它们。
function newAutotable(dim)
local MT = {};
for i=1, dim do
MT[i] = {__index = function(t, k)
if i < dim then
t[k] = setmetatable({}, MT[i+1])
return t[k];
end
end}
end
return setmetatable({}, MT[1]);
end
-- Usage
local at = newAutotable(3);
print(at[0]) -- returns table
print(at[0][1]) -- returns table
print(at[0][1][2]) -- returns nil
at[0][1][2] = 2;
print(at[0][1][2]) -- returns value
print(at[0][1][3][3]) -- error, because only 3 dimensions set
它们不太好的地方在于它们生成了很多个表格——很明显。这是一些内存开销,并且每个深度级别都会增加执行时间。
它们的优点在于它们的大小可以完全动态化。你甚至可以让它们无限深。尽管在您的用例中,这很可能没有必要,甚至可能是个坏主意。
尽管这种结构非常适合非整数索引,例如,您可以使深度甚至依赖于“模板结构”,从而实现透明的动态配置表,但我有点跑题了……
扁平化数组
另一个变体是扁平数组。 user3125367 已经写过关于它们的文章,但我想对此进行扩展,因为这样可以更方便地完成并解释一些事情。
在 CG 中通常展平多维数组是一个好主意,因为这样您就可以非常轻松地进行许多矩阵运算。就所需的处理时间而言,计算修改后的索引也相对便宜。但应该注意,虽然有点明显,但这种方法仅适用于数字键和预定义的矩阵大小。
function newMdArray(X, Y, Z)
local MT = { __call = function(t, x, y, z, v)
if x>X or y>Y or z>Z or x<1 or y<1 or z<1 then return; end
local k = x + X*(y-1) + X*Y*(z-1);
if v ~= nil then t[k] = v; end
return t[k];
end };
return setmetatable({}, MT);
end
-- Usage
local mdt = newMdArray(100, 100, 100);
local v = mdt(1, 2, 3);
mdt(1, 2, 3, v*.1);
此代码取自我的另一个答案:dynamic tables or arrays
它可能可以优化一点(例如在闭包中计算X*Y)但我想将原始代码粘贴到这里。无论如何,有了这个,您都可以通过使用普通数组索引轻松地处理扁平结构:
for i=1, #mdt
mdt[i] = (mdt[i] or 0)*.5
end
以及直接访问 3d 索引:
mdt(12, 13, 14, 0)
您还可以通过将__index 字段添加到元表或表格保存矩阵维度等来轻松修改函数以返回缺失键的默认值。