2017-09-01 73 views
2

我正在處理大量用Lua編寫的數據文件。他們大多是用這種方式,「電話本」爲例: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 

但我認爲這種做法可能是壞的,因爲它使整個線程活着只是爲了遍歷一個該死的表格以特定的方式。

有沒有其他「明顯」的解決方案呢?關鍵是性能和易用性。我並不完全需要一個通用的解決方案(對於數據表內的任意數量的「級別」),但是這一切都像黑客一樣下跌。

+1

可不可以給你心目中的查詢的例子嗎? – lhf

回答

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 
+0

這可能比我喜歡的更緊湊,但我想我可以看到該方法的一般要點,謝謝。也喜歡多次返回而不是像我一樣將數據混合在一起。 – dzikakulka

0

你可以在Lua中創建自己的自定義迭代器,不需要使用協程。迭代器是被調用的函數,返回結構中的下一個元素(可以使用任何你想要的結構)。

您例如迭代器是類似的東西:

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 
+0

非常感謝!如果我理解正確,這會保持數據表的副本作爲迭代器函數的上限,對吧?這一切都非常清楚和直接,好:) – dzikakulka