I need a fancy iterator that traverses through all the nested tree of a table.
I preferably want this with an iterator factory so that it can be reused.
Something like this
table = {{{ stuff=value},{}}, {{{},{stuff=value2}}} ,{},{{}}}
iter_function = whatver magic is here
local stuff
for tbl in iter_function(table) do
stuff = tbl.stuff
end
local table = {{{ stuff=value},{}}, {{{},{stuff=value2}}} ,{},{{}}}
local function iter( t, fn )
fn(t)
for v,k in pairs( t ) do
if type(k) == "table" then
iter( k, fn )
end
end
end
iter( table, print )
When traversing nested tables, I feel that recursion is the way to go and passing a function parameter you probably could make it quite dynamic, but I don't think you can make one for all solution to it.
At least I guess it would be a start to your question, maybe not complete solution. Also you could take a look at next(i,v) for creating an iterator. http://www.lua.org/manual/2.4/node31.html
What I want is some wizardry to make it work with for and be generic.
I already have a reclusive function solution for the problem.
Your solution is pretty good,better then what I have currently.
local function process(value,key)
if (type(value)=="table") then
for k,v in pairs(value) do
process(v,k)
end
else
coroutine.yield(key,value)
end
end
local function tree(root)
return coroutine.wrap(process),root
end
function love.load()
local test = {{{ stuff=123},{}}, {{{},{stuff=345}}} ,{},{{}}}
for leaf,value in tree(test) do
print(leaf,value)
end
end
local function process(value,key)
if (type(value)=="table") then
for k,v in pairs(value) do
process(v,k)
end
else
coroutine.yield(key,value)
end
end
local function tree(root)
return coroutine.wrap(process),root
end
function love.load()
local test = {{{ stuff=123},{}}, {{{},{stuff=345}}} ,{},{{}}}
for leaf,value in tree(test) do
print(leaf,value)
end
end
I am not sure, the reason I wanted tbl is because I wanted to evaluate at any point of the tables.
This looks like it will only get stuff key not the individual tables.
In reality I am using a class systems with lots of variables and functions and references contained in the table and the access to the table tree that I want iterated is in the form of table.children.
Its getting closer to what I want.
adrix89 wrote:I am not sure, the reason I wanted tbl is because I wanted to evaluate at any point of the tables.
This looks like it will only get stuff key not the individual tables.
In reality I am using a class systems with lots of variables and functions and references contained in the table and the access to the table tree that I want iterated is in the form of table.children.
Its getting closer to what I want.
Hence why I said your example doesn't make sense, you have to define what values you want to work with in your for loop. I can tell you straight up at this point you're doing something incredibly wrong.
local function process(value)
if (type(value)=="table") then
coroutine.yield(value)
for k,v in pairs(value) do
process(v)
end
end
end
local function traverse(root)
return coroutine.wrap(process),root
end
function love.load()
local test = { { {x, stuff=123},{x,stuff=3 }}, {stuff=23 ,{ {x },{x, stuff=345}}} ,{x,stuff=1},{ {x }}}
for tbl in traverse(test) do
print(tbl.stuff)
end
end
I can give you another solution just modifying my original post. Here we are passing a function as a parameter, because this way you only need to traverse the whole table through once unlike on the solution where you build new table, then traverse that table through
local test = { { {x, stuff=123},{x,stuff=3 }}, {stuff=23 ,{ {x },{x, stuff=345}}} ,{x,stuff=1},{ {x }}}
local table = {{{ stuff=value},{}}, {{{},{stuff=value2}}} ,{},{{}}}
local function iter( t, fn )
fn(t)
for v,k in pairs( t ) do
if type(k) == "table" then
iter( k, fn )
end
end
end
function love.load()
print( "Table!")
iter( table, (function( f ) print(f.stuff) end ) )
print( "Test!")
iter( test, (function( f ) print(f.stuff) end ) )
-- Or bit more complicated, summing all stuff values:
local sum = 0
iter( test,
( function( f )
if( f.stuff ) then
sum = sum + f.stuff
end
end ) )
print( "sum:" .. sum)
end
One problem with iterating nested tables is that (usually) you need to know the 'scope' in addition to the key and the value.
A while ago I wrote a library for accessing nested tabled. It uses "cocatecated sting keys" as described here. Just make sure to get the code from the repo as the version on the forums may be slightly out of date.
It works with cyclic tables too.
Recursion is probably mandatory for this thing.
My implementation is non-recursive (see table.gckeys). I used breadth-first traversal with a queue.