Lua嵌套for循环使用table.insert出现重复条目问题求解
问题背景
我目前仍在学习Lua,大概率存在更简便的方式可以实现目标。以下是我从代码中提取的片段,目前90%的功能符合预期,但在最后一步遇到了问题。
inv = {} for i = 23,mq.TLO.Me.NumBagSlots()+22 do inv[i] = {} for j = 1,mq.TLO.Me.Inventory(i).Container() do inv[i][j]={Item=mq.TLO.Me.Inventory(i).Item(j),bag=i,slot=j} end end local sortthatsucker={} for _,bags in pairs(inv) do for _,invcontainer in pairs(bags) do for _,_ in pairs(invcontainer) do local compactstring = tostring(invcontainer.Item).."-"..tostring(invcontainer.bag).."_"..tostring(invcontainer.slot) if tostring(invcontainer.Item) ~= "NULL" then table.insert(sortthatsucker,compactstring) end end end end table.sort(sortthatsucker) for k,v in pairs(sortthatsucker) do print(k,"-",v) end
当前代码已经可以按需求提取、过滤、排序所有物品,生成包含物品名称和对应“坐标”的复合字符串,得到可按名称排序的简易键值对表;但提取数据时使用的三层嵌套for循环,导致table.insert会在最终表中生成三条完全相同的条目,仅每个条目的键值不同。
示例输出如下:
163-shovel-23_10 164-shovel-23_10 165-shovel-23_10 166-tonsils-18_5 167-tonsils-18_5 168-tonsils-18_5 169-withers-6_12 170-withers-6_12 171-withers-6_12
我的目标是让该表中每个找到的物品仅对应单条条目,后续我会编写新的嵌套循环从字符串中提取背包、槽位坐标值,与对应坐标的物品交互并将其移动到新的坐标位置。如果有方式可以直接创建初始表并直接交互,无需构建嵌套表即可实现同等效果会更好,我经过两周的尝试和搜索仍未找到解决方法。
问题根因
重复条目的来源是多余的第三层for循环:
- 构建的
inv[i][j]本身就是单条物品记录,内部一共只有Item/bag/slot3个键 - 第三层循环
for _,_ in pairs(invcontainer) do会遍历这3个键,相当于每个物品会执行3次插入逻辑,自然会生成3条完全相同的记录
修复方案
最小改动版
直接删除多余的第三层循环即可,不需要改动其他逻辑:
inv = {} for i = 23,mq.TLO.Me.NumBagSlots()+22 do inv[i] = {} for j = 1,mq.TLO.Me.Inventory(i).Container() do inv[i][j]={Item=mq.TLO.Me.Inventory(i).Item(j),bag=i,slot=j} end end local sortthatsucker={} for _,bags in pairs(inv) do for _,invcontainer in pairs(bags) do local compactstring = tostring(invcontainer.Item).."-"..tostring(invcontainer.bag).."_"..tostring(invcontainer.slot) if tostring(invcontainer.Item) ~= "NULL" then table.insert(sortthatsucker,compactstring) end end end table.sort(sortthatsucker) for k,v in pairs(sortthatsucker) do print(k,"-",v) end
优化版(无需构建嵌套中间表)
完全可以跳过inv嵌套表的构建,遍历背包槽位时直接把有效物品加入待排序列表,减少不必要的内存占用:
local sortthatsucker = {} local bagEnd = 22 + mq.TLO.Me.NumBagSlots() for bagId = 23, bagEnd do local bag = mq.TLO.Me.Inventory(bagId) local slotCount = bag.Container() for slotId = 1, slotCount do local item = bag.Item(slotId) if tostring(item) ~= "NULL" then table.insert(sortthatsucker, ("%s-%s_%s"):format(tostring(item), bagId, slotId)) end end end table.sort(sortthatsucker) for k,v in pairs(sortthatsucker) do print(k,"-",v) end
如果后续需要直接操作坐标,甚至不用拼接字符串,直接存带itemName/bag/slot字段的表,排序时按物品名排序即可,省掉后续拆分字符串的步骤:
local itemList = {} local bagEnd = 22 + mq.TLO.Me.NumBagSlots() for bagId = 23, bagEnd do local bag = mq.TLO.Me.Inventory(bagId) local slotCount = bag.Container() for slotId = 1, slotCount do local item = bag.Item(slotId) local itemName = tostring(item) if itemName ~= "NULL" then table.insert(itemList, { name = itemName, bag = bagId, slot = slotId, itemObj = item }) end end end -- 按物品名排序 table.sort(itemList, function(a, b) return a.name < b.name end) -- 后续直接遍历拿坐标即可,不需要拆分字符串 for idx, itemInfo in ipairs(itemList) do print(idx, "-", itemInfo.name, itemInfo.bag, itemInfo.slot) -- 直接调用itemInfo.bag、itemInfo.slot即可做物品移动操作 end
内容的提问来源于stack exchange,提问作者KyleB
相关产品推荐
相关产品推荐

