Finding object inside nested table

Hello there!
I’m trying to find an object (player name and id) inside a table with multiple dictionaries inside of it. The object is supposed to be inside one of said dictionaries.
To do so, I used a recursive\deep search function I found here on the DevForum, but unfortunately it keeps returning false, as if the object i’m looking for wasn’t inside the table I pass.

This is the resursive\deep search function in question:

local function deepSearch(t, key_to_find)
	for key, value in pairs(t) do
		if value == key_to_find then
			return true,t
		end

		if typeof(value) == "table" then
			return deepSearch(value, key_to_find),nil
		end	
	end
	return false,nil
end

This is the function where I run the aforementioned function and insert the player name and user id. Basically, i use the deepSearch() function to check if the player is already inside one of the dictionaries.

Corrosion.Stages = {{},{},{},{}} --table with dictionaries where i story the players

function Corrosion:triggerStage(plr:Player,corrosion:number,oldCorrosion)
	local stage = self:getStage(plr,corrosion)
	
	if stage >= 1 and stage <= 4 then
		local isPresent,tb = deepSearch(self.Stages,plr.UserId)
		
		if not isPresent then
			self.Stages[stage][plr.Name] = plr.UserId
			local corrosionStage = require(script:FindFirstChild(tostring(stage)))
			corrosionStage:Start(plr)
			warn("just logged")
		
		elseif isPresent then
			warn("player found inside one of dictionaries")
			local oldStage = self:getStage(plr,oldCorrosion) print(stage,oldStage)
			if stage ~= oldStage then
				self.Stages[oldStage][plr.Name] = nil
				self.Stages[stage][plr.Name] = plr.UserId
				local stageOld = require(script:FindFirstChild(oldStage))
				local stageNew = require(script:FindFirstChild(stage))
				stageOld:End(plr)
				stageNew:Start(plr)
				print("is this even working?")
			end
		end
	elseif stage == 0 then
		warn("not enough corrosion!!")
		local isPresent,tb = deepSearch(self.Stages,plr.UserId)
		if isPresent then
			tb[plr.Name] = nil
			local oldStage = self:getStage(plr,oldCorrosion)
			require(script:FindFirstChild(tostring(oldStage))):End(plr)
		else
			warn("i just logged sis")
		end
	end	
	
	print(self.Stages)
end

Does anyone know if I’m doing anything wrong? Perhaps I’m indexing the player inside one of the dictionaries the wrong way, hence why it returns false?

EDIT: this is where I got the deepSearch() function

Is it a problem with the function? Set up the table yourself and see if it works then.

local t = {{a=0},{b=1},{c=2}}
local function deepSearch(t, key_to_find)
	for key, value in pairs(t) do
		if value == key_to_find then
			return true,t
		end

		if typeof(value) == "table" then
			return deepSearch(value, key_to_find),nil
		end	
	end
	return false,nil
end

print(deepSearch(t, 1))

If this works in the console, you’ll need to check that the table actually contains the proper user ID.

image
I think it’s a problerm with the function at this point, because it should return true and the second dictionary in this case, right?

I believe it does because when I printed the content of the table, the correct ID was displayed.

Maybe try this…?

local function deepSearch(t, key_to_find)
	for key, value in pairs(t) do
		if value == key_to_find then
			return true,t
		end

		deepSearch(value, key_to_find) 
	end
	return false,nil
end

You can add the type check, what I meant is don’t do return deepSearch.

I see the issue. I’ve fixed it as well as made the function slightly more practical.

local function deepSearch(t, key_to_find)
	for key, value in pairs(t) do
		if value == key_to_find then
			return t, key
		end
		if typeof(value) == "table" then
-- Original function always returned results of deepSearch here, but we should not return unless it is not nil.
			local a, b = deepSearch(value, key_to_find)
			if a then return a, b end
		end	
	end
	return nil
end

Now instead of returning true/false which is generally unnecessary, it returns either the table and the key of the found value, or just nil.
Example usage:

local returnedTable, key = deepSearch(tab, userId)
if returnedTable then
    if type(key) == "number" and math.floor(key) == key then
        table.remove(returnedTable, key) -- it's an array
    else
        returnedTable[key] = nil -- it's a dictionary
    end
end
1 Like

That seems to work perfectly! Thank you so much.

May I know why you consider it unnecessary? Is it a bad practice?

1 Like

In Lua, things are considered “truthy” and will pass if statements so long as they aren’t nil and aren’t false. So if a value exists, it will pass an if statement.

if returnedValue then

Even in most other languages it doesn’t make much sense to return a separate value. Either the function is successful and returns something, or it doesn’t return something. You don’t need a true/false to tell you that it didn’t find anything.

1 Like