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

我正在处理很多用Lua编写的数据文件。其中大多数都是这样写的,例如“电话簿”:

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,对吗?这一切都非常清晰和直接,很好:)这可能比我喜欢的要紧凑一些,但我想我可以看到该方法的一般要点,谢谢。也喜欢多重返回,而不是像我一样将数据混合在一起。