我有一个函数,它可以动态地改变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
我知道它的评论不是很好但是它的想法是它创建了一个具有更改维度的新表,然后在新表上叠加块数据,最后用新临时表覆盖块。
长度宽度和高度改变一个,递增或递减,但一次只改变一个。
我不确定我是否清楚地解释了它,如果不让我知道,我会尝试更详细地解释。
谢谢大家, 詹姆斯
答案 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