2017-09-01 8 views
2

私は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に作成できます。コルーチンを使用する必要はありません。イテレータは、呼び出されると構造体から次の要素を返す関数です(必要な構造体を使用できます)。

あなたの例のためのイテレータは、そのようなものになるだろう:「corIter」によって返された匿名関数は、あなたのデータから次の要素を返します

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 

。エントリを反復するために '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