Table library question

Just wondering why

local t = {
	{5, 2},
	{2, 3},
	{7, 2}
}

print(table.find(t, {5, 2}))

prints nil, instead of 1.

I know that each table has a unique ID and that I can get around this with

local function findTableInArray(array, needleTable)
	local ocurrenceIndex
	
	for i, tabl in array do
		local match = true
		
		for j, v in tabl do
			if needleTable[j] ~= v then match = false break end
		end
		
		if match == true then
			ocurrenceIndex = i
			break
		end
	end
	
	return ocurrenceIndex
end

or

local v = {5, 2}

local t = {
	v,
	{2, 3},
	{7, 2}
}

print(table.find(t, v))

when I say “why” it’s more like “What are the use cases”, because I can’t think of any.

just a random doubt lol

I’d say it’s probably to do with the way things are stored in memory.

When you have two variables that point to the same memory location, if you edit one in such a way it updates the value held at that memory location, it would update the second variable which also references that value.

So, whenever you have multiple tables of {5, 2}, they aren’t the same tables, just like you said with the UniqueId. You can have many tables that contain the same elements and appear identical, but they’re all held at different memory locations.

So, when you try to get an index of a seemingly identical table, they are two different tables, so they are held at different locations, which means they are not the same, resulting in a nil index.

yeah i dont see any use cases either, i only use tables in tables for constants or queueing, and even then i just store them in variables so i can use table.find

If you want to print 1, you’ll need to use a bit of a workaround. It’s a lot of effort for such a small task, but you’ll need to use custom metatables.

Here’s an approach you could consider using:

local function createTableWithEqualityCheck(tbl)
	local mt = {
		__eq = function(t1, t2)
			if #t1 ~= #t2 then return false end
			for i = 1, #t1 do
				if t1[i] ~= t2[i] then
					return false
				end
			end
			return true
		end
	}
	setmetatable(tbl, mt)
	return tbl
end

local t = {
	createTableWithEqualityCheck({5, 2}),
	createTableWithEqualityCheck({2, 3}),
	createTableWithEqualityCheck({7, 2})
}

print(table.find(t, createTableWithEqualityCheck({5, 2}))) -- Should print 1

Edit: I only read the first line of text, my bad :wink:

That makes sense :sweat_smile:

So if this UniqueId didn’t exist and I had different tables {5, 2} and modified only one of them all others would change?

Let’s say

local a = {5, 2}
local b = {5, 2}
local c = {5, 2}

Changing b would change a and c also?


That’s what I thought when I read your reply :joy: :joy:

Dw though, it’s alright :wink: .

If the tables’ UniqueId didn’t exist.

No.

Variables and constants are pointers to locations in the memory. If two items you are modifying sit at different memory locations, modifying one won’t modify the other.

Please note that if you reference one memory location to two variables, and then un-assign or modify one of them, it creates a new place in memory for it whilst maintaining the other one as long as it is referenced.

A good example is running this code in your command bar:

local a = {3}; local b = a; table.insert(a, 3); print(b)

In the output, you should get:

{
    [1] = 3,
    [2] = 3
}

This is because both these variables point to the same memory location, the same table. Of course, items are spread out across many memory locations, but for example’s sake I’m referencing it as one.




But, if you run this:

local a = {3}; local b = {3}; table.insert(a, 3); print(b)

you should get:

{
    [1] = 3
}

They are two seperate memory locations, two seperate pieces of data. If you initialised a table with {5, 3} and modified it without table’s UniqueIds, well, I’m pretty sure the code would not even run (I’m like 95% sure UniqueId is also a location to memory, if you’re on about table: 0x000)

1 Like

Every table is a distinct object.

local x = {1,2} -- table x
local t = {1,2} -- table t
print(x==y) -- false, because it's checking if table x is table t. It isn't. Every table is it's own object

When you use table.find, you’re essentially iterating over the table, and checking if the value is equal to whatever you want to find

function find(t,value)
  for i,v in t do
    if v==value then
      return i
    end
  end
end

But now you are using a table as a value, and like I said before tables aren’t equal even if they have the same content, because every table is a unique object. So we can just iterate over the table and check like this.

local function tablesEqual(t1, t2)
    if #t1 ~= #t2 then
        return false
    end
    for i = 1, #t1 do
        if t1[i] ~= t2[i] then
            return false
        end
    end
    return true
end

local t = {1,2}
local x = {1,2}
print(tablesEqual(t, x))  -- Output: true

There’s a problem with this. It only checks for tables one time. So it only accommodates a depth of 1. To fix, make it recursive.

local function tablesEqual(t1, t2)
    -- Check if both tables are the same reference
    if t1 == t2 then
        return true
    end

    -- Check if both t1 and t2 are tables
    if type(t1) ~= "table" or type(t2) ~= "table" then
        return false
    end

    -- Check the number of keys in both tables
    local function tableLength(tbl)
        local count = 0
        for _ in pairs(tbl) do
            count = count + 1
        end
        return count
    end

    if tableLength(t1) ~= tableLength(t2) then
        return false
    end

    -- Compare each key and value
    for key, value1 in pairs(t1) do
        local value2 = t2[key]
        
        -- Check if the key exists in both tables
        if value2 == nil then
            return false
        end
        
        -- Recursively check for equality of nested tables
        if type(value1) == "table" and type(value2) == "table" then
            if not tablesEqual(value1, value2) then
                return false
            end
        elseif value1 ~= value2 then
            return false
        end
    end

    return true
end

-- Example usage
local t1 = {1, 2, {a = 3, b = {4, 5}}}
local t2 = {1, 2, {a = 3, b = {4, 5}}}
local t3 = {1, 2, {a = 3, b = {4, 6}}}

print(tablesEqual(t1, t2))  -- Output: true
print(tablesEqual(t1, t3))  -- Output: false
1 Like

Yeah, that’s exactly what I was referring to when I mentioned UniqueId, just didn’t know the proper name.


That’s pretty cool, thanks for the insight!

So It’s more about memory than coding use cases, is that correct?


I mentioned this in the main post, I know why that happens, was just wondering if it had a reason, which 12345koip explained, that’s why I’ll mark his answer as the solution, but thanks to everyone who replied!

1 Like

Yeah, it’s essentially how things are stored in memory. If there’s one thing you should take away, it’s that variables and constants are pointers to locations in memory, and do not store the value themselves. (unless, of course, you already knew that!)

'better' definitions

A variable is a pointer to a location in memory that can change throughout runtime of a program.



A constant is a pointer to a location in memory that does not change throughout runtime of a program.

(by “change”, I mean reference a different memory location)

1 Like

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