Lua中的三维表

use*_*283 2 arrays lua multidimensional-array lua-table

我需要最好的方法来存储像素的三维表。我需要做的是有多个 x,y 表(基本上是 3 维)它是光栅化多个具有透明度的二维像素图。你看我可以像这样轻松地创建两个维度:

pixels = {{},{}}
pixels[1][5] = "green" --just an example
print(pixels[1][5])
Run Code Online (Sandbox Code Playgroud)

但是,我不能像在 Java 中那样做到这一点......

pixels = {{}, {}, {}}
pixels[1][4][3] = "red" -- [x][y][z]
print(pixels[1][4][3])
Run Code Online (Sandbox Code Playgroud)

这是我想要的功能,但我通过这样做令人作呕地解决了这个问题......

pixels = {}
pixels["x23,y02,z05"] = "green"
print(pixels["x23,y02,z05"]")
Run Code Online (Sandbox Code Playgroud)

我只是使用 string.sub 和 string.concat 来读取和设置表格...我真的希望示例 2 的功能能够工作,但是我知道它可能需要以不同的方式实现。

dua*_*led 5

基本上有两种方法可以解决这个问题

自动表格

自动表使用元表透明地生成子表,基本上在创建它之后你应该能够忘记它们。

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
Run Code Online (Sandbox Code Playgroud)

它们的不好之处在于它们生成了很多表——很明显。这是一些内存开销,每个深度级别都会增加执行时间。

它们的优点在于它们的大小可以是完全动态的。你甚至可以让它们无限深。尽管在您的用例中,这很可能没有必要,甚至可能是个坏主意。

不过,这种结构非常适合非整数索引,例如,您可以使深度甚至依赖于“模板结构”,从而实现透明的动态配置表,但我正在偏离轨道...

扁平化阵列

另一个变体是展平数组。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);
Run Code Online (Sandbox Code Playgroud)

此代码取自我的另一个答案:动态表或数组

它可能可以优化一点(例如X*Y在闭包中计算),但我想将原始代码粘贴到此处。无论如何,有了这个,您只需使用普通数组索引即可轻松处理扁平结构:

for i=1, #mdt
    mdt[i] = (mdt[i] or 0)*.5
end
Run Code Online (Sandbox Code Playgroud)

以及直接访问 3d 索引:

mdt(12, 13, 14, 0)
Run Code Online (Sandbox Code Playgroud)

您还可以通过向__index元表添加字段或以便表保存矩阵维度等来轻松修改函数以返回缺失键的默认值。