Lua,自定义迭代器-正确的定义方式?
我正在处理很多用Lua编写的数据文件。其中大多数都是这样写的,例如“电话簿”:Lua,自定义迭代器-正确的定义方式?,lua,iterator,Lua,Iterator,我正在处理很多用Lua编写的数据文件。其中大多数都是这样写的,例如“电话簿”: data = { -- First Level - country USA = { -- Second level - city Denver = { -- Third level - actual entries {name = 'John', number = '12345'}, -- more
data = {
-- First Level - country
USA = {
-- Second level - city
Denver = {
-- Third level - actual entries
{name = 'John', number = '12345'},
-- more entries
},
Washington = {
{name = 'Ann', number = '54321'},
-- more entries
},
-- more cities with entries
},
-- more countries with cities and entries
}
因此,第一级是“国家”,第二级是“城市”这一事实是隐含的,但它使数据更加紧凑
现在,在实际搜索一些数据时,我想将这些数据作为条目进行迭代,包括这个级别的隐式信息
-- Coroutine yielding entries including level data
function corIter(data)
for country,l1 in pairs(data) do
for city,l2 in pairs(l1) do
for _,entry in pairs(l2) do
-- Copy the entry
local out = {}
for k,v in pairs(entry) do
out[k] = v
end
-- Add level properties
out.country = country
out.city = city
coroutine.yield(out)
end
end
end
end
-- Iterate over the entries
local cor = coroutine.create(corIter)
local _, entry = coroutine.resume(cor, data)
while entry do
-- Handle the entry, has 'name', 'number', 'country' and 'city' keys
table.print(entry) -- (custom print function I use)
-- Get the next one
_, entry = coroutine.resume(cor)
end
但我认为这种方法可能不好,因为它只以特定的方式在一个该死的表上迭代,就让整个线程保持活动状态
有没有其他“明显”的解决办法?关键在于性能和易用性。我并不需要一个通用的解决方案(对于数据表中任意数量的“级别”),但这一切都像是一个黑客。您可以在Lua中创建自己的自定义迭代器,无需使用协同程序。迭代器是调用时返回结构中的下一个元素的函数(您可以使用任何想要的结构)
local function phones(d)
local cn, c, tn, t, i
return
function()
local a
repeat
if tn then
a, i = t[i], i+1
if not a then
i, tn, t = 1, next(c, tn)
end
else
cn, c = next(d, cn)
i, tn, t = 1, next(c or {})
end
until a or not cn
return cn, tn, a
end
end
for country, town, abonent in phones(data) do
print(country, town, abonent.name, abonent.number)
end
您示例中的迭代器如下所示:
function corIter(data)
local itOut = {};
for country,l1 in pairs(data) do
for city,l2 in pairs(l1) do
for _,entry in pairs(l2) do
-- Copy the entry
local out = {}
for k,v in pairs(entry) do
out[k] = v
end
out.country = country
out.city = city
table.insert(itOut,out)
end
end
end
local i = 0
return function()
i = i + 1
return itOut[i]
end
end
end
“corIter”返回的匿名函数将从数据中返回下一个元素。请注意,当我们使用“pairs”将条目复制到另一个表中对其进行迭代时,没有任何东西可以保证条目的顺序将保持原始顺序
现在您可以使用此代码打印条目:
for entry in corIter(data) do
print(entry) -- this is a table
for k,v in pairs(entry) do
print(k,v) -- these are the actual values
end
end
你能举一个你想问的问题的例子吗?非常感谢!如果我理解正确的话,这会将数据表的副本保留为迭代器函数的upvalue,对吗?这一切都非常清晰和直接,很好:)这可能比我喜欢的要紧凑一些,但我想我可以看到该方法的一般要点,谢谢。也喜欢多重返回,而不是像我一样将数据混合在一起。