Page 1 of 2

Nested Table Iterator

Posted: Tue Dec 30, 2014 5:15 pm
by adrix89
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

Code: Select all

table = {{{ stuff=value},{}}, {{{},{stuff=value2}}} ,{},{{}}}
iter_function = whatver magic is here
local stuff
for tbl in iter_function(table) do
    stuff = tbl.stuff
end

Re: Nested Table Iterator

Posted: Tue Dec 30, 2014 6:52 pm
by Muris
I guess youre not accepting recursive function as an answer and passing a function inside? Something along the line of:

Code: Select all

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

Re: Nested Table Iterator

Posted: Tue Dec 30, 2014 9:01 pm
by adrix89
Recursion is probably mandatory for this thing.

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.

Re: Nested Table Iterator

Posted: Tue Dec 30, 2014 10:33 pm
by Azhukar
adrix89 wrote:I need a fancy iterator that traverses through all the nested tree of a table.
Something like this? Your example didn't really make sense.

Code: Select all

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

Re: Nested Table Iterator

Posted: Tue Dec 30, 2014 10:55 pm
by adrix89
Azhukar wrote:
adrix89 wrote:I need a fancy iterator that traverses through all the nested tree of a table.
Something like this? Your example didn't really make sense.

Code: Select all

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.

Re: Nested Table Iterator

Posted: Wed Dec 31, 2014 12:52 am
by Azhukar
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.

Re: Nested Table Iterator

Posted: Wed Dec 31, 2014 8:58 am
by adrix89
Yes! I manged to modify it to work.

Code: Select all

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

Re: Nested Table Iterator

Posted: Wed Dec 31, 2014 11:28 am
by Muris
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

Code: Select all


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


Re: Nested Table Iterator

Posted: Wed Dec 31, 2014 2:03 pm
by Azhukar
Muris wrote:unlike on the solution where you build new table
There is no such solution in this thread.

Re: Nested Table Iterator

Posted: Thu Jan 01, 2015 6:45 am
by ivan
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.