How would I deep compare two tables, were the keys and values can be values such as vector3, cframe etc

So I have made a serializer for a datastore I am working on, and I have made a function that just generates tons of jibrish and random values. I want to to do some tests and see if everything works, so after a serialize the table, and deserialize it, I want to check if the deserialized table matches the start table. The key value cannot be a table value, but can be any other value. The table can be nested with multiple tables

local t = {}
for x = 1,14 do
	--getRanValue can return a vector3, vector2, CFrame, Color3.fromrgb, bool, number, string, or a table value containing random getRanValue() values
	local key, val = getRanValue(0, true), getRanValue(0)
	t[key] = val
end
local serialized = storageFunctions.serialize(t)
local deSerialized = storageFunctions.deSerialize(serialized)
--I need a function that can check if these two tables are equal
print(equal(serialized , deSerialized)) -- returns true if have the same data, or false if not
1 Like

I mean I could code the function myself, but I was wondering if anyone had a function to do this already, I tried to find the functions myself, but it seemed like all of them only compares the values. Idk maybe I should look better.

1 Like

That’s what metatables are really best for.

When the recipient gets the table, they bind it to a metatable and you can then compare the contained values with a for loop

local newTable = setmetatable(givenTable, {})
for key,val in pairs(givenTable) do
    if newTable[key] == val then
        print(newTable[key], '---', givenTable[key])
    end
end
1 Like

Just gave it a try using recursion, tell me if you find any bugs:

local function equal(t1: {}, t2: {}): boolean
	local s1, s2 = 0, 0
	--checking if the keys amount is different
	for i, v in pairs(t1) do s1 += 1 end
	for i, v in pairs(t2) do s2 += 1 end
	if s1 ~= s2 then return false end
	--checking if the values are different
	for key, value in pairs(t1) do
		if type(value) ~= "table" then
			if t2[key] ~= value then return false end
		else
			if type(t2[key]) ~= "table" then return false end
			if not equal(t2[key], value) then return false end
		end
	end
	--if none are different, the tables context is the same
	return true 
end

Also if your tables only store basic data types like numbers, strings, bools and tables(like the type of data you can save in a data store) you can just compare the JSON encoded version of both tables:

local function encode(t: {}): string
	return game.HttpService:JSONEncode(t)
end
--Assuming that the table doesn't contain instances or complicated data types
local function equal(t1: {}, t2: {}): boolean
	return encode(t1) == encode(t2)
end
1 Like

Hmm I think it works, but it returns false, would be nice if it maybe like returned true/false, and then the 2keys or 2 values that didn’t match etc, but I will try to shorten the random table and manualy look, but thank you so much!

This’ll return true if equal. It’ll also list out why things aren’t equal.

function compareTables(t1 : {}, t2 : {})
	local diff = {}
	for k,v in t1 do
		if t2[k] == nil then
			table.insert(diff, k .. " exists for t1 but not for t2")
		elseif typeof(v) ~= typeof(t2[k]) then
			table.insert(diff, "Type for v mismatch: t1 is " .. tostring(typeof(v)) .. "; t2 is " .. tostring(typeof(t2[k])))
		elseif t2[k] ~= v then
			table.insert(diff, "Value for k mismatch: t1 is " .. tostring(v) .. "; t2 is " .. tostring(t2[k]))
		end
	end
	return #diff == 0 or diff
end

-- Test
local x = {123, Vector3.one} local y = {123, Vector3.zero}
print(compareTables(x,y)) 
--  [1] = "Value for k mismatch: t1 is 1, 1, 1; t2 is 0, 0, 0"

local x = {123, Vector3.zero} local y = {123, Vector3.zero}
print(compareTables(x,y)) 
-- true

local x = {123, Vector3.zero} local y = {123, CFrame.new(1,2,3)}
print(compareTables(x,y))
--  [1] = "Type for k mismatch: t1 is Vector3; t2 is CFrame"