动态表格或数组

我有一个可以动态改变3D数组或表大小的函数,但它一直失败,因为它返回值空,因为它越界。以下是它的代码:

function resize()
    temp = { }
    for h=1, height do
        table.insert( temp , { } )
        for y=1, length do
            table.insert ( temp[h], { } )
            for x=1, width do
                num = 16
                if #blocks <= height then
                    if #blocks[h] <= length then
                        if #blocks[h][y] <= width then
                            num = blocks[h][y][x]
                        end
                    end
                end
                table.insert( temp[h][y] , num )
            end
        end
    end
    blocks = temp
end

我知道它没有很好地注释,但它的思想是创建一个具有改变尺寸的新表,然后在新表上重叠块的数据,最后用新的临时表覆盖块。

长度、宽度和高度仅仅是逐一增加或减少一个。

如果我没有表述清楚,请告诉我,我将尽力更详细地说明。

谢谢大家, 詹姆斯

点赞
用户2198692
用户2198692

我认为错误出现在你的 if 语句里面。你应该对块的大小与 h、y 和 x 进行比较,而不是高度、长度和宽度。

另外,不要在可以使用 temp[h] = {} 替代 table.insert 时使用它,这样可以更快。另外,尽量使用局部变量进行 temp 存储。

2013-06-04 20:59:01
用户1990152
用户1990152

我不确定这是否是最好的方法,但它确实有效。

function resize()
temp = {} -- 临时表

-- 插入所有高度级别
for h = 1,height do table.insert(temp,{})end

-- 插入所有长度
for h = 1,height do
    for l = 1,length do table.insert(temp [h],{})end
end

-- 插入所有宽度并将其默认为0
for h = 1,height do
    for l = 1,length do
        for w = 1,width do table.insert(temp [h] [l],0end
    end
end

-- 如果画布大小增加
if #blocks <= height then
    if #blocks [1] <= length then
        if #blocks [1] [1] <=宽度 then
            for h = 1,#blocks do
                for l = 1,#blocks [1] do
                    for w = 1,#blocks [1] [1] do
                        -- 填充来自块的数据
                        temp [h] [l] [w] = blocks [h] [l] [w]
                    end
                end
            end
        end
    end
end

--如果画布大小减小
if #blocks> = height then
    if #blocks [1]> = length then
        如果#blocks [1] [1]> =宽度 then
            for h = 1,#temp do
                for l = 1,#temp [1] do
                    for w = 1,#temp [1] [1] do
                        -- 从块填充数据,但不要填入最后一个值
                        temp [h] [l] [w] = blocks [h] [l] [w]
                    end
                end
            end
        end
    end
end

--用新的尺寸覆盖块
blocks = temp
2013-06-05 06:02:40
用户1244588
用户1244588

你的特定错误(可能)

你没有对 nil 值进行测试。任何未初始化的表格(在本例中为数组)成员都是按定义 nil。与数字比较 nil 会生成错误:

lua: attempt to compare nil with number

然而,由于你似乎无法提供 实际 的错误信息,所以这只是一个猜测。不要误解,这些是你代码中的错误,但可能还有 _其他问题_,我忽视了它们。无论如何,以下是一些关于你的代码的注释,以展示发生了什么。

if #blocks <= height then              -- 假设 #blocks 是 3,height 是 4
    if #blocks[h] <= length then       -- E: 在迭代 4 中 blocks[h] 是 nil
        if #blocks[h][y] <= width then -- E: 在 it. 3,4 中 blocks[h][y] 是 nil
            num = blocks[h][y][x]
        end
    end
end

你必须首先在每个级别上对 nil 进行测试,例如

if blocks[h] and blocks[h][y] and blocks[h][y][x] and
       #blocks[h]<=height and #blocks[h][y]<=height and #blocks[h][y][x]<=height
    num = blocks[h][y][x]
end

一般编程错误

blockslengthwidthheight 似乎是函数的参数,但却不在它的标题中,因此我想在调用该函数之前你将它们设置为外部变量?这当然不是好的做法。

tempnum 应该声明为 local

替代方案

你可以使数据结构更加智能,例如,如果你将 3D 数组放在一个扁平化的表格中,并添加一个 __call 元方法,如下所示

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 nil 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

然后这就是你要做的只是制作一个调整大小的副本:

function resizeMdArray(array, X, Y, Z)
    local r = newMdArray(X, Y, Z);
    for x=1, X do
        for y=1, Y do
            for z=1, Z do
                r(x, y, z, array(x, y, z) or 16);
            end
        end
    end
    return r;
end

一个不错的奖励是,这个数据结构将 3D 数组扁平化为 1D 数组,如果你只想 复制 数据,你只需将其视为表格进行访问并复制每个元素:

for i=1, X*Y*Z do
    new[i] = old[i]
end

当然,你可以使用“真正”的(隐藏的)3-D 数组来进行完全相同的操作,从而避免算术计算,但是那样你将不得不一直测试空值以防止 nil 错误。

2013-06-05 14:15:33