Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Help regarding dictionaries - Why can't you use tables as keys?

So, for a 2D tile-based game I've been creating I want to use dictionaries to index individual tiles. But the problem is, I can't use tables or Vector2's as keys, as I'd like to.

I'm trying to do something like this:

map = {
	[{0,0}] = "tile" -- 'tile' object at 0,0
}

But whenever I try to print the value using this:

local x = 0
local y = 0
print(map[{x,y}]) -- prints tile at the 0,0 coordinate

It always returns nil.

I have found a hacky workaround, however. I could just turn the X and Y components of the table into a string, like so:

map = {
	["00"] = "tile"
}
local x = 0
local y = 0
print(map[tostring(x)..tostring(y)])

It works but it's a rather inelegant solution that I might as well scrap for something more organized.

Any help would be appreciated.

1 answer

You can use tables as keys but the reason why you keep getting nil when trying to retrieve the info stored at that key is that in lua tables are compared by "reference" i dont know the right term, basically where it is stored in the memory. It doesnt compare their content when checking for equalness.

So recap:

print( {} == {}) --false

local tbl = {}
local tbl2 = tbl
print(tbl ==tbl2 ) --true

local dict = {}

local dictKey = {0,1}

dict[dictKey] = "Yes"

print(dict[dictKey]) -- prints Yes

To make it work your case:

local C00 = {0, 0}
local map = {
    [C00] = "tile"
}

print(map[C00])

Ofcourse this isnt convenient,

so i recommend that you use nested table, as in

example 2x2:


local map = {
	{},
	{}
}
map[1][1] = "tile"
map[1][2] = "Tile2"

print(map[1][2]) -- Tile2

or other option is use a metatable, where you can define its equalness using __eq metamethod but you still cant use this as they key for a dict


local mt = {}

function mt.__eq(tbl, value) -- very basic equalness, doesnt work for dicts or arrays with tables as value
	if type(value) ~= "table" or #tbl ~= #value then return false end
	
	for i = 1, #tbl do
		if tbl[i] ~= value[i] then
			return false
		end
	end
	return true
end


local C1 = setmetatable({0,0}, mt)
local C2 = setmetatable({0,0}, mt)

local map = {
	[C1] = "tile" -- 'tile' object at 0,0
}

print(map[C2], map[C1] , C1 == C2) -- nil, tile, true

This discussion is preserved as it was. New answers, comments, and votes are closed.