How to Check if Two or More Dictionaries are Equal

I am trying to make a function that takes in a table and a tuple of more tables. What I want to do with these tables is, if they are dictionaries, check if the dictionaries contain the same keys. So I am trying to see if they equal each other basically. I tried this method, but remembered dictionaries aren’t ordered so I knew I had to take a different approach.

-- Bad method
function TableUtil:Equals(tab1,...)
	local tab1 = HttpService:JSONEncode(tab1)
	for _,tab in pairs({...}) do
		if tab == nil or tab1 ~= HttpService:JSONEncode(tab) then
			return false
		end
	end
	return true
end

I came to the conclusion that I needed to do this recursively, but I am stuck on how I would exactly do it. There are barely to none resources about this online for Roblox. How can I do this recursively?

If you say dictionaries I will assume you have strings as keys.

Simple method, might not be optimal.

function check(d1, d2)

    for k, v in pairs(d1) do
        if d2[k] != v then return false end
    end

    for k, v in pairs(d2) do
        if d1[k] != v then return false end
    end

    return true
end

EDIT: My code checks if the dictionaries have the same values too. If you are interested in keys only then check if non-nil values correspond to non-nil values.

EDIT: as @nicemike40 pointed out pairs works for both scenarios.

1 Like

I think you need pairs there for string keys too.

Yeah sorry I meant to say values as well, but wouldn’t it get a little messy if the values were tables then I would have to recursively check those tables and/or dictionaries right? no?

This has some good info.

1 Like

It is true, in that case it gets a bit more complicated but it is still possible with recursion.

True, I messed up, I am editing now the reply.

From the link I posted:

function deepcompare(t1, t2, ignore_mt)
    local ty1 = type(t1)
    local ty2 = type(t2)
    if ty1 ~= ty2 then return false end
    -- non-table types can be directly compared
    if ty1 ~= 'table' and ty2 ~= 'table' then return t1 == t2 end
    -- as well as tables which have the metamethod __eq
    local mt = getmetatable(t1)
    if not ignore_mt and mt and mt.__eq then return t1 == t2 end
    for k1, v1 in pairs(t1) do
        local v2 = t2[k1]
        if v2 == nil or not deepcompare(v1, v2) then return false end
    end
    for k2, v2 in pairs(t2) do
        local v1 = t1[k2]
        if v1 == nil or not deepcompare(v1, v2) then return false end
    end
    return true
end

Which you could use like

function TableUtil:Equals(tab1, ...)
    for _, t in pairs({...}) do
        if (not deepcompare(tab1, t, true)) then
            return false
        end
    end

    return true
end

edit: This will work but it’s pretty dumb :slight_smile: If you really need to compare arbitrary numbers of tables at once, it would probably be better to generalize deepcompare so you’re comparing all the tables at each level. That way, you wouldn’t be doing as much unnecessary comparisons.

3 Likes

I managed to create a working version for my case of your example. Thanks a lot! Credit to mike as well for posting an alternate solution.

1 Like

function CheckEqual(Table1, Table2)
for i,v in pairs(Table1) do
if v != Table2[i] then return false end
end
return true
end

Just encode the tables in JSON, compare the strings. I don’t see why it wouldn’t work.

There are more than one JSON strings that correspond to the same dictionary. Encoding them to JSON might give different results for the same tables.

That doesn’t make any sense. If you have table a, and table b, and they are the same, the JSON strings will be the same. If the tables are different, they will not be the same.

It makes perfect sense. I will give you an example so you can understand. Say we have two strings that represent json encodings of some tables:

s1 = "{'key1': 1234, 'key2': 5678}"
s2 = "{'key2': 5678, 'key1': 1234}"

These 2 strings will decode to the same lua tables. However the strings themselves are different.

3 Likes

Recursion would be the best option in this case.