Recurisve Search?

My brain is kind of exploding because I can’t really imagine what this would be like.

I have a table of tables of tables - it can be any number of sub tables and sub tables within those sub tables. You don’t know. Here’s the table

[lua]PATHS = {
NAME = “Base”,
TEXTURE = “”,
WEAPONS = {},
CLASSES = {

[1] = {
	NAME = "Bourgeois",
	TEXTURE = "", 
	CLASSES = {
		[1] = {
			NAME = "Cook",
			CLASSES = {
				[1] = {
					NAME = "Chef",
					CLASSES = {},
					SKILLS = {
					
					},
				},
			},
			SKILLS = {
			
			},
		},
	},
	SKILLS = {
	
	},
	WEAPONS = {
		"weapon_physcannon",
		"gmod_camera",
	},
},

[2] = {
	NAME = "Intellectual",
	TEXTURE = "", 
	CLASSES = {
	
	},
	SKILLS = {
	
	},
	WEAPONS = {
		"weapon_physcannon",
		"gmod_camera",
	},
},

[3] = {
	NAME = "Military",
	TEXTURE = "", 
	CLASSES = {
	
	},
	SKILLS = {
	
	},
	WEAPONS = {
		"weapon_physcannon",
		"gmod_camera",
	},
},

},

}[/lua]

I’m trying to make a function, PATHS:GetPathByName, that finds the table of the path if the name is equal to the argument. How exactly would you do that?

oops Rate me bad spelling, I meant recursive.

:psyboom:

[editline]02:33AM[/editline]

“Bourgeois”…I sense RP…and it has bourgeois so it must be epic :smiley:

You probably want to look at how PrintTable works :
http://luabin.foszor.com/code/lua/includes/util.lua#30

Though you probably could come up with a better indexing system.

You could do something like:

[lua]
function gpbn(path, tbl)
for k,v in pairs(tbl)
if v.NAME && v.NAME == path then
return v
end

	if v.CLASSES && #v.CLASSES > 0 then
		gpbn(path, v)
	end
end

end[/lua]

You’d probably have to modify it to fit the structure of your tables though.

Or you could go with the more straightforward way of including a “base” field for all of the classes and storing them all in the same table. That way you can access them directly by their index (which would be their name) and they will be just as (if not more) easy to organize.

[editline]12:44AM[/editline]

It just makes sense that it’s better to reference things directly then having to look for them all of the time. Another way would be keeping your structures keeping a reference to each element in a properly string indexed table so that you already have a path to them handy.

I do already have a system in place for directly referencing something, and it’s how I refer to a path: both paths and skills are referred to by an integer with the number of digits corresponding to the level in the table. For example, the “cook” class has an ID of 11. Here’s the function I use:

[lua]function PATHS:GetPathByID( id )
id = string.Explode("",id)
local ret = self
for i = 1, #id do
ret = ret.CLASSES[tonumber(id*)]
end
return ret
end[/lua]

…However, I haven’t done much on this scale before. Is there a better way to do this?

About the PrintTable thing, the problem lies in that I’m trying to return something, so whenever I re-call the GetPathsByname function I have to return it to keep the loop running, if that makes sense. Here’s what I have so far:

[lua]function PATHS:GetPathByName( name, root )
if not root then root = self end
if string.lower(name) == string.lower(root.NAME) then return root end
for _,v in pairs( root.CLASSES ) do
print(v.NAME)
if string.lower(v.NAME) == string.lower(name) then return v end
return self:GetPathByName( name, v )
end
end[/lua]

But the problem with that is that is it only goes through the first item in each layer – bourgeois, cook, then chef. It didn’t go through any of the other layers. (is this perhaps a time I should use coroutines or whatnot?)

Just an interesting idea I had. I’m trying to stay away from the typical “RP” construct with cut and dry “classes” you have to be. This will (hopefully) be somewhat more dynamic and interesting.

The code me and Yaka gave you use the same base principle, you loop through a table and if you find another table you loop through it too until you’ve found the value you’re looking for. You do that by calling the function again with the newfound table as a parameter. And so that you don’t have ro do any of that index your classes by their name instead of an ID so you don’t have any searching to do.

But how would you index it by strings and still get the same efficiency as by numbers? With numbers, it’s as simple as table[a]**[c], but with strings I’d have still have to search through each table to see if the index is equal to the name.

-snip

Well using your system of jamming unnamed tables into one another you could do this : [lua]local ref = {}
ref[“Bourgeois”] = PATHS[1]
ref[“Cook”] = PATHS[1][1]
ref[“Chef”] = PATHS[1][1][1][/lua]
That way it would be easy to reference to a specific table.

But if I were you I’d scratch that table structure and do something like this :
[lua]
CLASSES = {
Base = {
TEXTURE = “”,
WEAPONS = {}
},
Bourgeois = {
TEXTURE = “atexture”,
SKILLS = {
},
WEAPONS = {
“weapon_physcannon”,
“gmod_camera”,
},
BASE = CLASSES.Base
},
Cook = {
SKILLS = {“Make pizza”}
BASE = CLASSES.Bourgeois
}
}

local function GetAttribute(class,attr) – This functions gives looks through a class and all of it’s bases until it finds a value. If no values are present it will just return nil.
if !class then return end
return class[attr] or GetAttribute(class[“BASE”],attr)
end

function LoadClass(class)

local class = CLASSES[class]
if !class then return end

local texture = GetAttribute(class,"TEXTURE") or "defaulttexture"
local skills = GetAttribute(class,"SKILLS") or {"breath","walk"}
local weapons = GetAttribute(class,"WEAPONS") or {"fists"}

return texture,skills,weapons

end

–This will not only print the attribute of cook, but it will also look inside it’s bases if no value is found.
print(LoadClass(“Cook”))

–Direct access to a specific table
print(CLASSES.Cook)[/lua]

I think you were kind of looking at the problem backwards. After all a class doesn’t need to contain references to it’s childs in order to load, but to it’s parents.

Hmm. You bring up an interesting point. Ok, thanks Quebec, I’ll see what I can do with this.