0

我有一个旨在动态更改 3D 数组或表的大小的函数,但它一直说它返回值 nil 因为它超出了界限。这是它的代码:

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

我知道它的评论不是很好,但想法是它创建一个具有更改尺寸的新表,然后将块的数据叠加在新表上,最后用新的临时表覆盖块。

长度宽度和高度以递增或递减的方式更改,但一次只能更改一次。

我不确定我是否解释得足够清楚,如果没有让我知道,我会尝试更详细地解释。

谢谢大家,詹姆斯

4

3 回答 3

1

我认为错误在于您的 if 语句。您应该根据 h、y 和 x 来确定块的大小,而不是高度、长度和宽度。

附带说明一下,当您可以用 temp[h] = {} 替换 table.insert 时,不要使用它。它更快。另外,尝试使用本地人进行临时存储。

于 2013-06-04T20:59:01.490 回答
1

您的具体错误(可能)

您不会针对 nil 值进行测试。任何未初始化的表(在这种情况下为数组)成员都是nil根据定义的。与数字比较nil会产生错误:

lua: attempt to compare nil with number

但是,由于您似乎无法提供实际的错误消息,这只是一个猜测。不要误会我的意思,这些是您的代码中的错误,但可能还有我忽略的其他错误。无论如何,这里有一些注释以及您的代码,以向您展示发生了什么

if #blocks <= height then              -- say #blocks is 3, height is 4
    if #blocks[h] <= length then       -- E: in iteration 4 blocks[h] is nil
        if #blocks[h][y] <= width then -- E: in it. 3,4 blocks[h][y] is 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

一般编程错误

blocks, length,width并且height似乎是您的函数的参数,但不在其标题中,所以我想您在调用函数之前在外部设置它们?这当然不是好的做法。

temp并且num应该声明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 数组执行相同操作,从而节省算术计算,但是您必须始终测试空值以防止出现零错误。

于 2013-06-05T14:15:33.207 回答
0

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

function resize()       
temp = { } -- temp table

-- inserting all the height levels
for h=1, height do table.insert( temp , { } ) end

-- inserting all the lengths
for h=1, height do
    for l=1, length do table.insert( temp[h], { } ) end
end

-- inserting all the width and defaulting them to 0
for h=1, height do
    for l=1, length do
        for w=1, width do table.insert( temp[h][l] , 0 ) end
    end
end

-- if the canvas size is increasing
if #blocks <= height then
    if #blocks[1] <= length then
        if #blocks[1][1] <= width then
            for h=1, #blocks do
                for l=1, #blocks[1] do
                    for w=1, #blocks[1][1] do
                        -- fill in data from blocks
                        temp[h][l][w] = blocks[h][l][w]
                    end
                end
            end
        end
    end
end

--if the canvas size is decreasing
if #blocks >= height then
    if #blocks[1] >= length then
        if #blocks[1][1] >= width then
            for h=1, #temp do
                for l=1, #temp[1] do
                    for w=1, #temp[1][1] do
                        -- fill in data from blocks but not the last value
                        temp[h][l][w] = blocks[h][l][w]
                    end
                end
            end
        end
    end
end

-- overwrite blocks with the new dimensions
blocks = temp
于 2013-06-05T06:02:40.453 回答