这个问题与
How can I safely iterate a lua table while keys are being removed类似,但明显不同。
概要
给定一个Lua数组(具有从1开始的顺序整数的键的表),迭代这个数组并删除一些条目的最佳方式是什么?
现实世界的例子
我在Lua数组表中有一个timestamped条目数组。条目总是添加到数组的末尾(使用table.insert)。
local timestampedEvents = {} function addEvent( data ) table.insert( timestampedEvents,{getCurrentTime(),data} ) end
我需要偶尔运行这个表(按顺序),并处理和删除某些条目:
function processEventsBefore( timestamp ) for i,stamp in ipairs( timestampedEvents ) do if stamp[1] <= timestamp then processEventData( stamp[2] ) table.remove( timestampedEvents,i ) end end end
不幸的是,上面的代码打破了迭代,跳过了一些条目。有没有比手动走索引更好(更少打字,但仍然安全)这样做
function processEventsBefore( timestamp ) local i = 1 while i <= #timestampedEvents do -- warning: do not cache the table length local stamp = timestampedEvents[i] if stamp[1] <= timestamp then processEventData( stamp[2] ) table.remove( timestampedEvents,i ) else i = i + 1 end end end
解决方法
the general case of iterating over an array and removing random items from the middle while continuing to iterate
只需使用table.remove。但是,如果您从头到尾迭代,则当您删除元素N时,迭代中的下一个元素(N 1)会向下移动到该位置。如果你增加迭代变量(如ipairs),你将跳过该元素。有两种方法可以处理这个问题。
使用此示例数据:
input = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p' } remove = { f=true,g=true,j=true,n=true,o=true,p=true }
我们可以通过以下方式在迭代中删除输入元素
>从后面到前面迭代
for i=#input,1,-1 do if remove[input[i]] then table.remove(input,i) end end
>手动控制循环变量,所以我们可以在删除元素时跳过它:
local i=1 while i <= #input do if remove[input[i]] then table.remove(input,i) else i = i + 1 end end
对于非数组表,您可以使用下一个或多个对(以下一个方式实现)迭代,并将要删除的项设置为零。