How can I loop through a table in lua, which has an arbitrary number of nested tables within it, so that I can access all of its data?
To clarify, my data structure would look something like this:
[CODE]table = {
table2 = { table5 = { value4, value5 }}
table3 = { value1, value2 }
}[/CODE]
I did some research on this and came to no comprehensible solutions.
If I'm not being clear enough I'll be glad to try to explain further.
This may be better suited to the programming forum since it's not really specific to gmod, so sorry if this isn't the right place.
[lua]
function iterate(table)
for k,v in pairs(table) do
if type(v)=="table" then
iterate(v)
else
--dostuff
end
end
end
iterate(table)
[/lua]
that should work
Thanks. That was a lot easier then I was expecting it to be for some reason, heh heh.
So it seems like I underestimated how difficult the next part in my plan would be...
Basically, I have data stored as a table in an entity, which uses other entity references as its keys (among other data).
The entities referenced there can have their own table of entity references, and so on and so forth so that we get recursion to an arbitrary depth.
What I need to do is compile a single table with entity references as keys, and set the value of each of those entries to its entity data.
So for instance, I'd have my data spread out more or less like this:
[CODE]e5 = "some other value"
e4.objects = {[e5] = true}
e3 = "some value"
e2.objects = {[e4] = true}
e1.objects = {[e2] = true, [e3] = true}[/CODE]
And I need to get a table of the form
[CODE]e1.objects = {[e2] = {[e4] = {[e5] = "some other value"}}, [e3] = "some value" }[/CODE]
Is this possible or should I just change my data structure?
[QUOTE=Mossman1223;42026932]So it seems like I underestimated how difficult the next part in my plan would be...
Basically, I have data stored as a table in an entity, which uses other entity references as its keys (among other data).
The entities referenced there can have their own table of entity references, and so on and so forth so that we get recursion to an arbitrary depth.
What I need to do is compile a single table with entity references as keys, and set the value of each of those entries to its entity data.
So for instance, I'd have my data spread out more or less like this:
[CODE]e5 = "some other value"
e4.objects = {[e5] = true}
e3 = "some value"
e2.objects = {[e4] = true}
e1.objects = {[e2] = true, [e3] = true}[/CODE]
And I need to get a table of the form
[CODE]e1.objects = {[e2] = {[e4] = {[e5] = "some other value"}}, [e3] = "some value" }[/CODE]
Is this possible or should I just change my data structure?[/QUOTE]
i really think you need to change your data structure
You should probably explain what your end goal is - this seems like a mess.
[QUOTE=Kogitsune;42027398]You should probably explain what your end goal is - this seems like a mess.[/QUOTE]
It's an inventory system in which any container can contain another container within its inventory and so on(Hence the Matryoshka joke). I've gotten things working pretty well so far, but decided to shift from keeping content data in the root container's table to keeping each entity's content data in its own, separate table (entity2.contents rather than entity1.contents[entity2].contents), to make transfers simpler.
Of course the issue I ran into is that I need the single contents table for the root container for stuff like saving tables, and sending to the client to build the UI.
I'm just going to build that single table like I did earlier but keep the entity.contents structure as well just to make transferring containers around simpler - There's more overhead generally since I'm essentially indexing the same data twice but it's the best way I've thought of so far to do it.
[QUOTE=Mossman1223;42027540]It's an inventory system in which any container can contain another container within its inventory and so on(Hence the Matryoshka joke). I've gotten things working pretty well so far, but decided to shift from keeping content data in the root container's table to keeping each entity's content data in its own, separate table (entity2.contents rather than entity1.contents[entity2].contents), to make transfers simpler.
Of course the issue I ran into is that I need the single contents table for the root container for stuff like saving tables, and sending to the client to build the UI.
I'm just going to build that single table like I did earlier but keep the entity.contents structure as well just to make transferring containers around simpler - There's more overhead generally since I'm essentially indexing the same data twice but it's the best way I've thought of so far to do it.[/QUOTE]
should store the contents of it as tables.
for example
entity1.contents = {{id="container",name="entity2",contents = {{id="item",name="entity3"}}},{id="item",name="entity4"}}
[lua]
function SlotInfoFromEntity(ent)
local slotinfo = {}
slotinfo.name = ent:GetClass().."/"..ent:GetModel() --default name
--other slotinfo defaults here
if ent.inventorydata then slotinfo = ent.inventorydata end --if the entity has data just use that
return slotinfo
end
function EditInventory(inventory,slotx,sloty,ent_to_go_inside_inventory)
local inv = inventory.slots
inv[slotx] = inv[slotx] || {}
inv[slotx][sloty] = SlotInfoFromEntity(ent_to_go_inside_inventory)
end
[/lua]
Something like that. Just make each level into the inventory be considered its own inventory. So you could have player.inventory.slots[2][4].name as "chainsaw with pockets", and player.inventory.slots[2][4].slots[9][2] be another item that could also have an inventory.
[editline]31st August 2013[/editline]
example
local inventory = player.inventory[2][7]
EditInventory(inventory,7,5,car)
[QUOTE=Bletotum;42028207][lua]
function SlotInfoFromEntity(ent)
local slotinfo = {}
slotinfo.name = ent:GetClass().."/"..ent:GetModel() --default name
--other slotinfo defaults here
if ent.inventorydata then slotinfo = ent.inventorydata end --if the entity has data just use that
return slotinfo
end
function EditInventory(inventory,slotx,sloty,ent_to_go_inside_inventory)
local inv = inventory.slots
inv[slotx] = inv[slotx] || {}
inv[slotx][sloty] = SlotInfoFromEntity(ent_to_go_inside_inventory)
end
[/lua]
Something like that. Just make each level into the inventory be considered its own inventory. So you could have player.inventory.slots[2][4].name as "chainsaw with pockets", and player.inventory.slots[2][4].slots[9][2] be another item that could also have an inventory.
[editline]31st August 2013[/editline]
example
local inventory = player.inventory[2][7]
EditInventory(inventory,7,5,car)[/QUOTE]
Yes, but how can I edit a table value when I don't initially know how "deep" in a tree it's nested?
Edit: Something like this would work, I am thinking?
[CODE]function table.FindAndSet( tab, target, value )
for k,v in pairs(tab) do
if k == target then
tab[k] = value
return
end
if type(v) == "table" then
table.FindAndSet( tab, target, value )
end
end
end[/CODE]
You should probably step away from storing it in a nest format at all.
Instead, each item should have m_bIsInContainer and m_hContainer properties.
All items that are in a player's possession, but not in a sub-container, would have m_bIsInContainer as true and m_hContainer would be a reference to their inventory table.
So, to get all items in a container, you'd do this:
[code]
function GetInventory( container )
local k, v, t
t = { }
for k, v in pairs( Inventory.ItemList ) do
if not v.m_bIsInContainer then
continue
end
if v.m_hContainer ~= container then
table.insert( t, v )
end
end
return t
end[/code]
You would need to do is give containers a unique id so they are distinguishable, though.
By having a flat table, you don't need to know how deep in a tree the item is - you can find all items in a given container without having to navigate it.
Might be a better way, but it seems straight forward.
[QUOTE=Kogitsune;42031307]You should probably step away from storing it in a nest format at all.
Instead, each item should have m_bIsInContainer and m_hContainer properties.
[/QUOTE]
Does the m_b and m_h prefix have any special significance?
[QUOTE=Kogitsune;42031307]
[code]
for k, v in pairs( Inventory.ItemList ) do
if not v.m_bIsInContainer then
continue
end
[/code]
[/QUOTE]
Can you explain the function of this? I've heard that this "continue" keyword is specific to gmod lua but I've never been able to find any more specific information about it.
Also, what is Inventory.ItemList here supposed to be?
Thanks for the reply, by the way.
m_b is what I use to represent booleans, and m_h is a pointer of some sort - an entity, table, or similar. You can name them whatever you want, of course.
Inventory.ItemList would be a list of all items that are being played - the ones in all containers - as a single, flat table.
Continue is a .Net keyword that tells it to skip the rest of the loop, more or less the same as:
[code]
if v.m_bIsInContainer then
if v.m_hContainer == container then
--Rest of loop
end
end[/code]
Just helps it look a little cleaner.
[QUOTE=Kogitsune;42031616]m_b is what I use to represent booleans, and m_h is a pointer of some sort - an entity, table, or similar. You can name them whatever you want, of course.
Inventory.ItemList would be a list of all items that are being played - the ones in all containers - as a single, flat table.
Continue is a .Net keyword that tells it to skip the rest of the loop, more or less the same as:
[code]
if v.m_bIsInContainer then
if v.m_hContainer == container then
--Rest of loop
end
end[/code]
Just helps it look a little cleaner.[/QUOTE]
Thanks for the tip.
Somewhat unrelated question now;
Are there any benefits to sending entity indexes (using net.WriteInt) rather than just using WriteEntity?
My assumption would be that that's what was being done internally anyway but I'm not sure.
[QUOTE=Mossman1223;42031495]Does the m_b and m_h prefix have any special significance?[/QUOTE]
That's called [url=http://en.wikipedia.org/wiki/Hungarian_notation]Hungarian Notation[/url]
It's just a naming convention that is entirely up to who is writing the code.
The only difference is convenience - it gets networked as the index anyways ( or at least it should ).
Sorry, you need to Log In to post a reply to this thread.