如何有效地从lua表中删除nil值
我是lua的新手,也是编程的新手。我正尝试实现以下功能。
我有一个从中选择随机数的数字表。
myTable = {}
for i = 1 to 100 do
table.insert(myTable, i)
end
local numberChosen = myTable[math.random(#myTable)]
到目前为止,都很好。下一次选择数字时,我希望该数字从表中删除。我知道lua不会删除值,它们作为空值保留。所以
table.remove(myTable, numberChosen)
不能用,因为如果值为空,我再次运行随机函数,就会得到 “bad argument #1 to 'random' (interval is empty)”
我已经尝试创建一个这样的函数:
function cleanTable(t)
local cleanTable = {}
for k, v in ipairs(t) do
if v ~= nil then
table.insert(cleanTable, v)
end
end
return cleanTable
end
myTable = cleanTable(myTable)
但是它也行不通,因为随机函数返回相同的错误。有人能帮忙吗?
编辑-----------------------------------------------------------------------
我的表包含如下键和值:
local columns = {1,2,3,4,5,6,7,8,9,10,11,12}
local rows = {1,2,3,4,5,6,7,8,9,10,11,12}
local coupledNumbers = {}
for i = 1,#columns do
for a = 1,#rows do
local coupledNumber = i * a
table.insert(coupledNumbers, i*a, coupledNumber)
end
end
如何删除键和值?谢谢
你可以使用键-值表格而不是数值表格。代码有点丑。
local columns = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
local rows = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
local coupledNumbers = {}
-- 和 `i = 1, 12` 一样,你甚至不需要表格 `columns` 和 `rows`,因为你不需要索引
for i = 1, #columns do
for j = 1, #rows do
local idx = i * j
if not coupledNumbers[idx] then
coupledNumbers[idx] = true
end
end
end
local function getRand(n)
local res
if next(coupledNumbers) ~= nil then
repeat
local r = math.random(n)
if coupledNumbers[r] then
res, coupledNumbers[r] = r, nil
end
until res
end
return res
end
print(getRand(144))
print(getRand(144))
print(getRand(144))
print(getRand(144))
print('---')
for i in pairs(coupledNumbers) do
print(i)
end
我倾向于采用生成一个棋盘(一个二维数组)的方式来解决这个问题,并在每次被击中时将每个元素设置为true。然后在选择每个命中时仅需检查该棋盘,如果它已经是true,那么它就是重击,如果是false,则为新的击中。
这是一开始的数组:
这是100个随机击中后的结果:
并不是所有的100个格子都被标记为true,因为其中很多都是重击,你可以从下面的控制台中看到:
你可以从“playGame”函数中的“boardHeight”和“boardWidth”修改棋盘大小,如果需要任何帮助将其集成,可以留言,我会帮助你。
local function getNewBoard(newHeight, newWidth)
local newBoard = {}
for i = 1, newHeight do
newBoard[i] = {}
for j = 1, newWidth do
newBoard[i][j] = false
end
end
return newBoard
end
local function playGame()
local boardHeight = 10 --将其更改为所需高度
local boardWidth = 10 --将其更改为所需宽度
local gameBoard = getNewBoard(boardHeight, boardWidth)
for _ = 1, 100 do
--获取一个随机的击中,您可以将其更改为玩家输入
local hitHeight = math.random(1, boardHeight)
local hitWidth = math.random(1, boardWidth)
if gameBoard[hitHeight][hitWidth] == true then --检查是否已经被击中
print("[" .. hitHeight .. ":" .. hitWidth .. "]已经被击中了")
else
gameBoard[hitHeight][hitWidth] = true --标记为已被击中
print("[" .. hitHeight .. ":" .. hitWidth .. "]刚刚被击中了")
end
end
end
playGame()
我知道 Lua 不会删除值,它们会作为 nil 存在。
不,它并不是这样工作的。根据文档,它是这样工作的:
table.remove函数会从给定的位置中删除并返回一个元素,并将其他元素下移以关闭空间并减少数组的大小。
-- https://www.lua.org/pil/19.2.html.
你的问题在于:
local randomPosition = math.random(#myTable) -- 获取随机位置
local numberChosen = myTable[randomPosition] -- 从该位置获取数值
table.remove(myTable, numberChosen) -- 尝试移除元素,但是实际上需要指定其位置,而不是某个在该位置找到的任意值。
你的逻辑第一次工作纯粹是巧合,只是因为你的数组恰好与其位置匹配。
你需要根据位置进行删除:table.remove(myTable, randomPosition)。
你的第二个函数不仅没有用,而且没有意义。for in ipairs 永远不会返回 nil 值 - 它是数组的末尾,因此 for 循环只会关闭。
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?




当你定义
numberChosen时有问题。当你定义local numberChosen = myTable[math.random(#myTable)]时,你错误地把
numberChosen定义为表中某个任意索引处的值。让我们来看一下你代码的几个循环
Loop: 1 numberChosen: 1 #myTable 100 Loop: 2 numberChosen: 57 #myTable 99 Loop: 3 numberChosen: 20 #myTable 98 Loop: 4 numberChosen: 82 #myTable 97 Loop: 5 numberChosen: 60 #myTable 96 Loop: 6 numberChosen: 48 #myTable 95 Loop: 7 numberChosen: 35 #myTable 94 Loop: 8 numberChosen: 91 #myTable 93 Loop: 9 numberChosen: 82 #myTable 92 Loop: 10 numberChosen: 74 #myTable 91 Loop: 11 numberChosen: 17 #myTable 90 Loop: 12 numberChosen: 86 #myTable 89 Loop: 13 numberChosen: 70 #myTable 88 Loop: 14 numberChosen: 49 #myTable 87 Loop: 15 numberChosen: 30 #myTable 86 Loop: 16 numberChosen: 3 #myTable 85 Loop: 17 numberChosen: 10 #myTable 84 Loop: 18 numberChosen: 38 #myTable 83 Loop: 19 numberChosen: 16 #myTable 82 Loop: 20 numberChosen: 17 #myTable 81 Loop: 21 numberChosen: 100 #myTable 80请注意,循环21发生了什么,我们有了数字100,这是一个不能存在的索引。我们从列表中移除了20个项目,所以列表只有80个项目长。
当我们调用
math.random(#myTable)时,我们将结果限制在我们表的范围内,但是当我们执行myTable[math.random(#myTable)]时,我们不再有这种信心。当我们从表中删除值时,它会缩小,但表内的值不会改变,导致引用超出我们表边界的索引值增加。
因此,我们需要将
numberChosen定义为math.random(#myTable)而不是myTable[math.random(#myTable)],此外,为确保我们具有唯一的索引值,我已更改了用于构建数组的 for 循环:local columns = {1,2,3,4,5,6,7,8,9,10,11,12} local rows = {1,2,3,4,5,6,7,8,9,10,11,12} local coupledNumbers = {} print(coupledNumbers == {}) for i = 1, #columns do for a = 1, #rows do local index = ((i - 1) * #rows) + a coupledNumbers[index] = index end end for i = 1, 144 do local numberChosen = math.random(#coupledNumbers) print(i, numberChosen, coupledNumbers[numberChosen]) table.remove(coupledNumbers, numberChosen) end