动态表或数组

时间:2013-06-04 13:49:12

标签: function lua lua-table

我有一个函数,它可以动态地改变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

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

长度宽度和高度改变一个,递增或递减,但一次只改变一个。

我不确定我是否清楚地解释了它,如果不让我知道,我会尝试更详细地解释。

谢谢大家, 詹姆斯

3 个答案:

答案 0 :(得分:1)

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

作为旁注,当你可以用temp [h] = {}替换它时,不要使用table.insert。它更快。另外,尝试使用locals进行临时存储。

答案 1 :(得分: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阵列展平为一维阵列,如果您只想复制数据,您可以通过简单地将其作为表格进行访问并复制每个元素:

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

当然,您可以在后台使用“真实”(隐藏)3-D数组执行相同操作,从而节省算术计算,但是您必须始终测试空值以防止出现nil错误。

答案 2 :(得分: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