How to compare dictionaries?

Hello everyone,

I got a dictionary that kinda looks like this:

dictionary = {
  item1 = 'sword',
  item2 = 'shield',
  item3 = 'helmet',
}

At some point in the game this dictionary will have different values and potentially different keys, so basically I need to be able to compare if the ‘new’ dictionary is different than the previous one.

I don’t need to know what did change, just need to know if the dictionaries are different.

I know how to do for arrays, but dictionaries are trickier (or I’m likely missing something really basic).

Thanks in advance.

This works but It will error if 1 dictionary is empty:

local Table1 = {
	Item1 = "Sword";
	Item2 = "Sheild";
	Item3 = "Helmet";
}

local Table2 = {
	Item1 = "Apple";
	Item2 = "Hotdog";
	Item3 = "Cheese";
}



function CompareTables(T1, T2)
	for i, v in pairs(T1) do
		if T2[i] ~= v then
			return true
		else
			return false
		end
	end
end

print(CompareTables(Table1, Table2))--prints true
print(CompareTables(Table1, Table1)) -- prints false

Since you’re returning right away, this just checks if the first key-value pair in the loop is the same. I don’t think that’s what you want.

3 Likes

I am aware of that, if you want to make a better version feel free to do so.

(Someone correct me if I say something that’s incorrect) You can’t compare two tables because every table is different, unlike simple data types like numbers and strings which can be compared.

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

You can iterate through all the values in one of the tables and check if the value in the other table is the same.

local tab1 = {Money = 1, Food = 2}
local tab2 = {Money = 1, Food = 3}

local alike = true
for name, val in pairs(tab1) do
	if tab2[name] ~= val then
		alike = false
	end
end

print(alike) -- false
2 Likes

Because you insisted,

function CompareTables(T1, T2)
    for k, v in pairs(T1) do
        if T2[k] ~= v then
            return true
        end
    end
    return false
end

You would only be checking if every value in t1 is equal to every value in t2, but you also have to check for any remaining keys in t2.

Given your tables are not too large, this should be efficient enough

function _compareTables(T1, T2)
    for k, v in pairs(T1) do
        if T2[k] ~= v then
            return true
        end
    end
    return false
end

function CompareTables(T1, T2)
    return _compareTables(T1, T2) or _compareTables(T2, T1)
end
2 Likes

Nice code! The only problem I see with it, is that if you switched the order of the elements in one of the tables, but still had the same values/strings, it would still indicate a change - which may not be a problem depending on what OP needs. An example:

local table1 = {"a", "s", "l"}
local table2 = {"l", "a", "s"}

local change = CompareTables(table1, table2)
print(change) --> Prints "true" despite the strings being the same ones re-ordered

Here’s a function I took some time to make just now, and it (I think) solves this problem, though it may be quite inneficient. So feel free to change the code however you want of course.

local function compareTables(t1, t2)
    local t1Copy = t1
    local t2Copy = t2

    for i = 1, #t1Copy, 1 do
        for j = 1, #t2Copy, 1 do
            if t2[j] == t1[i] then
                t1Copy[i] = nil
                t2Copy[j] = nil
                break
            end
        end
    end

    if #t1Copy > 0 or #t2Copy > 0 then
        return true -- True means there is a change
    end
    return false -- False means there is no change
end

This will make copies of the two tables - so when I refer to “table” from this point on I’m referring to the copies. It will loop through both tables, and every time it finds a match it’ll remove that specific element from both tables. If both tables have the same elements, it will end off on both tables having 0 elements and returning true. Otherwise, the tables will end up having more than 0 elements, and thus will return false, indicating that there was a change.

I hope I helped, and let me know if there’s any thoughts on this code.

EDIT: Sets elements to nil instead of using table.remove() now. And by the way, this code should work for number or string arrays.

3 Likes