How to index through nested tables using only function arguments

I came across this issue a long time ago and I had sort of just made a band aid solution to it by writing a bunch of if statements and told myself ill come back to it when i become a more compotent scripter. But clearly im not compotent enough because i still dont know how to do this. Im using profile service and im creating a set data function which takes in any number of arguements as the index keys. heres the code if you want to take a look.

function PlayerData:Set(Player, Value,...) 
	local Profile  = GetProfile(Player)
	local IndexKeys = {...}
	
	if IndexKeys[1] and Profile.Data[IndexKeys[1]] then
		
		
		if IndexKeys[2] and Profile.Data[IndexKeys[1]][IndexKeys[2]] then
			
			if IndexKeys[3] and Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]] then
				
				if IndexKeys[4] and Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]][IndexKeys[4]] then
					
					if type(Value) ==  type(Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]][IndexKeys[4]]) then
						Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]][IndexKeys[4]] = Value
						
					else
						warn("Value types did not  match;".. tostring(type(Value)).. " ".. tostring(type(Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]][IndexKeys[4]])))
						
					end
				else
					if type(Value) == type(Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]]) then
						Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]] = Value
						
					else
						warn("Value types did not  match;".. tostring(type(Value)).. " ".. tostring(type(Profile.Data[IndexKeys[1]][IndexKeys[2]][IndexKeys[3]])))
						
					end
				end
			else
				if type(Value) == type(Profile.Data[IndexKeys[1]][IndexKeys[2]]) then
					Profile.Data[IndexKeys[1]][IndexKeys[2]] = Value
					
				else
					warn("Value types did not  match;".. tostring(type(Value)).. ", ".. tostring(type(Profile.Data[IndexKeys[1]][IndexKeys[2]])))
					
				end
			end
		else	
			if type(Value) == type(Profile.Data[IndexKeys[1]]) then
				Profile.Data[IndexKeys[1]] = Value
				
			else
				warn("Value types did not  match;".. tostring(type(Value)).. ", ".. tostring(type(Profile.Data[IndexKeys[1]])))
			end
		
		end
	else
		warn("No indices given")
	end
end

Use a loop to navigate through the data, until you reach the final key, where you can then set the value.

function PlayerData:Set(Player, Value, ...) 
	local Profile  = GetProfile(Player)
	local IndexKeys = {...}
	 
	local entry = Profile.Data
	for i = 1, #IndexKeys - 1 do
		local nextKey = IndexKeys[i]
		entry = entry[nextKey]
		
		if entry == nil then
			warn("Could not find path")
			return
		end
	end
	
	local setKey = IndexKeys[#IndexKeys]
	entry[setKey] = Value
end

Here’s my attempt:

function PlayerData:Set(player, value, ...) 
	local Profile  = GetProfile(player)
	local indexes = {...}
	--this safety check ensures the loop below will run atleast once
	--this is so the old and oldIndex variables get values
	if #indexes == 0 or not Profile.Data[indexes[1]] then
		warn("No indices given")
		return
	end
	--this is the recursive process
	local current, old, oldIndex = Profile.Data, nil, nil
	for i = 1, #indexes do
		if not current[indexes[i]] then break end
		old, oldIndex = current, indexes[i]
		current = current[indexes[i]]
	end
	if typeof(value) == typeof(current) then
		--The reason we don't do current = value here is to ensure the table is updated by reference
		old[oldIndex] = value
	else
		warn("Value types did not  match;"..typeof(value).. ", "..typeof(current))
	end
end

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.