Finding value of a table inside a table

In short: I am looking for a method that works like :FindFirstDescendant() but with tables.

Example:

--Finding "Stat"
local Table = {
["Stats"] = { ["Stat"] = randomvalue }
}

In my case I would only have the key: ["Stat"] and the table.
["Stats"] is “anonymous” per say.

Any help is appreciated!

So you would loop over Table and see if Stat exists in a certain value.

2 Likes

I have thought of this but what I’m doing is comparing 2 tables to see if they are the same, if they aren’t then make them the same:
Example: Table1 is default and Table2 is not the same as default, finds the values that are missing in Table2 and add them.

Don’t know how I would do this in my case.

e.g.:

for i,v in pairs(Table) do -- this will loop through every Value inside the table.
    -- i is ["Stats"]
    -- v is the table
end

That’s what scripting is all about.

1 Like

I have thought of this but my table has a lot of subtables, what I don’t know is how to loop through every single one of them

Looping in tables to find a stat is unnecessary. Instead, you can simply index a table to find a value such as:

local Table = {["Stats"] = {}, Sally = 100}

if Table["Stats"] ~= nil then
--Execute code beyond here
end

To find subtables, it can be done without looping.

I use this method for saving data rather than keeping values in the player’s instance:

We have the stats table here:

local Stats = {
    Coins = 10,
    Diamonds = 5,
    NewTable = {
       Dog_Name = "Sally",
    },
}

To find the dog name in the subtable, you can simply index it by doing the following:

local DogName = Stats.NewTable.Dog_Name
print(DogName) --prints "Sally"
for i,v in pairs(rootTable) do
   local valueFound
   if type(v) == "table" and not v["Stats"] then
      local tableExists = v
      repeat wait()
         for i2,v2 in pairs(tableExists) do
            if type(v2) == "table" and not v2["Stats"] then
               tableExists = v2
            elseif type(v2) == "table" and v2["Stats"] then
               valueFound = v2["Stats"]
            end
         end
      until not tableExists or valueFound
      print(valueFound)
   end
end

Something like this is recursive but it is excessive and unnecessary - you should never be in a position where the amount of sub-tables you have is so needlessly complex that you need to use a solution like this.

Much better to write something along the lines of:

local Tbl = {[1] = {}, [2] = {},[3] = {}}
-- And indexing as:
print(Tbl[1],Tbl[2],Tbl[3])

Than it is to write something like:

local Tbl = {[1] = {[2] = {[3] = {}}}}
-- And indexing as:
print(Tbl[1],Tbl[1][2],Tbl[1][2][3])

Currently my table looks like this:

local DefaultData = {
		["Costumes"] = {
			["Dan"] = "false",
			
			["Alex"] = "false",
			
			["Emma"] = "false",
			
			["Princess"] = "false",
			
			["Betty"] = "false",
			
			["Matilda"] = "false",
			
			["Demon"] = "false",
			
			["Fairy"] = "false",
			
			["Angel"] = "false",
			
			["Candy Corn"] = "false",
		},
		
		["Currencies"] = {
			["Candy"] = 0
		},
		
		["EverPlayed"] = "false",
		
		["Current Costume"] = "",
		
		["Current BodyType"] = "",
		
		["Quests"] = {
			
			["Paranormal Hunter"] = {
				["Status"] = nil,
				["Progress"] = nil,
				["Cooldown"] = 0,
			},
			
			["Letter"] = {
				["Status"] = nil,
				["Progress"] = nil,
				["Cooldown"] = 0,
			},
		},
	}

I feel like I exaggerated a bit on saying a lot of subtables, don’t really know what is considered too much.

You have them all predefined: why loop in the first place?

You want the Status of Letter? It’s as simple as:

DefaultData.Quests.Letter.Status
2 Likes

Problem is what I’m doing doesn’t give me [“Quests”] or [“Letter”], only [“Status”].

Seems like you should reiterate your system then. Your system won’t work in the first place considering each of your quests has a “Status” member.

1 Like

I have that in mind, I plan on changing the keys to something like [“LetterProgress”] or something. However I would still not have [“Letter”] or [“Quests”]

Change the key to “Letter_Progress” and use:

string.split(key,"_")[1] --> "Letter"

There is no method available by default to solve this problem. However, I had this problem before so, I made a function to solve it for me. This may be of help x3

local selectField = function(targetTable, ...)
	for layers, key in next, {...} do
		local succ, _ = pcall(function() targetTable = targetTable[key] end)
		if not succ then
			error(("attempt to index nil with %s. %d layers deep."):format(typeof(key), layers), 2)
		end
	end
	return targetTable
end

-- example
local a = { b = { c = { 1 } } }
print(selectField(a, "b", "c")) --> 1

-- example2
local Table = {
	Stats = {
		Stat = "randomValue?"
	}
}

local Stats = selectField(Table, "Stats") 
print(Stats.Stat) --> randomValue?

If you don’t want it to throw a petty error because at some point in the nest it indexed nil, replace the error with a return. Most likely, a error message and also a boolean that is false. Then, change whenever successful it returns the value and true.

Edit: Better idea

1 Like

Currently I have to go to sleep, I will test tomorrow but it looks like it will work! Thanks.

Is there a reason as to why nobody suggested recursion? Makes your life much easier.

2 Likes

This solution also fixed the problem I had along with the one in this topic: