Lua,自定义迭代器 - 正确的定义方式?

时间:2017-09-01 18:58:26

标签: lua iterator

我正在使用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  

但我认为这种方法可能很糟糕,因为它保持一个完整的线程只是为了以特定的方式迭代该死的表。

还有其他"显而易见的"解决这个问题?关键在于性能和易用性。我并不需要一个通用的解决方案(任意数量的"级别"内部数据表),但这一切都像黑客一样崩溃。

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

您可以在Lua中创建自己的自定义迭代器,无需使用协程。迭代器是调用时的函数,返回结构中的下一个元素(可以使用任何你想要的结构)。

您的示例的迭代器将是这样的:

JRTextExporterParameter.PAGE_HEIGHT

'corIter'返回的匿名函数将返回数据中的下一个元素。请注意,当我们使用'pairs'将条目复制到另一个表来迭代它们时,没有任何东西可以保证条目的顺序将保持原始顺序。

现在您可以使用此代码打印条目:

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