Closed GniLudio closed 4 years ago
print(table.equals({a=12,b=2},{a=1,b=2}))
returns true
problem being every value being compared with every value...
@Jochnickel I don't know how you want to solve table comparison.
These things must be considered: 1) Multiple times the same value
{1,1,2} == {1,2}
2) Arrays and Dictionaries{[1]=1} == {1}
3) Compare keys and values?{[2]=1} =={[17]=1}
what it does now:
it checks if a table has exactly the same k-v pairs (recursive).
so {a={b=1}} == {a={b=1}}
i didnt respect arrays so far, so {[1]=1,[2]=2} ~= {[1]=2,[2]=1}
function table.compare(table1, table2)
if "table"~=type(table1) then error("1st argument of table.compare() is not a table") end
if "table"~=type(table2) then error("2nd argument of table.compare() is not a table") end
for k, v1 in pairs(table1) do
local v2 = table2[k]
if "table"==type(v1) and "table"==type(v2) then
if not table.compare(v1,v2) then return false end
else
if v1~=v2 then return false end
end
end
for k, _ in pairs(table2) do
local v1 = table1[k]
if v1==nil then return false end
end
return true
end
@Jochnickel I think you treat arrays already as indented.
1) Array
i could now introduce flags:
TABLE_COMPARE_STRICT = 0
TABLE_COMPARE_IGNORE_KEYS = 1
TABLE_COMPARE_IGNORE_KEYS_AND_DUPLICATES = 2
function table.compare(table1, table2, flags)
if "table"~=type(table1) then error("1st argument of table.compare() is not a table") end
if "table"~=type(table2) then error("2nd argument of table.compare() is not a table") end
if nil==flags or 0==flags then
-- as before
elseif TABLE_COMPARE_IGNORE_KEYS==flags then
local arr1 = {}
for _, v1 in pairs(table1) do
table.insert(arr1,v1)
end
-- arr1 is array with all table1 values
for _, v2 in pairs(table2) do
--checking every table2 value
local foundV1 = false
for k1, v1 in pairs(arr1) do
if v2==v1
or "table"==type(v1) and "table"==type(v2) and table.compare(v1,v2, flags)
then
-- found the counterpart in arr1
foundV1 = true
arr1[k1] = nil
break
end
end
if not foundV1 then
-- no arr1 counterpart found
return false
end
end
for _ in pairs(arr1) do
-- arr1 value is left with no table2 counterpart
return false
end
elseif TABLE_COMPARE_IGNORE_KEYS_AND_DUPLICATES==flags then
local values = {}
local tabValues1 = {}
for _, v1 in pairs(table1) do
if "table"==type(v1) then
-- v1 is a table
local tableAlreadyListed = false
for v0 in pairs(tabValues1) do
if table.compare(v1,v0,flags) then
tableAlreadyListed = true
break
end
end
if not tableAlreadyListed then
tabValues1[v1] = v1
values[v1] = 1
end
else
-- v1 is a normal value, not table
values[v1] = 1
end
end
-- so now all table1 values are stored as keys in values {12 = 1, "1a5" = 1,...}
-- also tabValues1 contains all different tables {table51 = table51, table32 = table32, ...}
-- for every tabValue1 there is an entry in values {..., "1a5" = 1, table51 = 1, ...}
for k2, v2 in pairs(table2) do
if "table"==type(v2) then
local foundV1 = false
for v1 in pairs(tabValues1) do
if table.compare(v1,v2,flags) then
foundV1 = true
values[v1] = 2
break
end
end
if not foundV1 then return false end
else
-- v2 is a normal value, not table
if nil==values[v2] then
-- lonely value2
return false
end
values[v2] = 2
end
end
-- now all 1 inside values should have turned into 2
-- values[normal values] == 2 now if they appeared in the 2nd table
-- values[tables] == 2 if there was a similar (sub)table in table2
for k,v in pairs(values) do
if 1==v then
-- lonely value1
return false
end
end
end
return true
end
@GniLudio now that looks like a lot, because its 2 different implementations
strict: {a=1,b=2} ~= {a=2,b=1}
as mentioned
ignore keys: {a=1,b=2} == {c=1,d=2}
but {a=1,b=2,z=2}~={c=1,d=2}
ignore keys and duplicates: {a=1, b=2, z=2} == {c=1, d=2}
and {a=1, z={2,3}} == {c=1, d={2,3}, f={2,3}}
@Jochnickel
Not perfect but a lot shorter I didn't test much but it should work... :)
function compare(table1, table2, flags)
if "table"~=type(table1) then error("The 1st parameter of compare() is not a table.") end
if "table"~=type(table2) then error("The 2nd parameter of compare() is not a table.") end
if "number"~=type(flags) then error("The 3rd parameter of compare() is not a number.") end
-- shouldn't be in the function...
local STRICT, IGNORE_KEYS, IGNORE_KEYS_AND_DUPLICATES = 0,1,2
-- IF STRICT --> COMPARE KEYS
if flags==STRICT then
print("STRICT")
-- Has table2 all keys of table1?
for k, _ in pairs(table1) do
if not table2[k] then return false end
end
-- Has table1 all keys of table2?
for k, _ in pairs(table2) do
if not table1[k] then return false end
end
-- IF KEYS ARE IGNORED --> CONVERT INTO VALUE--COUNT
else
-- convert table1
local t1_converted = {}
for k, v in pairs(table1) do
-- creates the value--0 pair
t1_converted[v] = t1_converted[v] or 0
-- if duplicates are not ignored --> count the value
if IGNORE_KEYS==flags then
t1_converted[v] = t1_converted[v]+1
end
end
table1 = t1_converted
-- convert table2
local t2_converted = {}
for k, v in pairs(table2) do
-- creates the value--0 pair
t2_converted[v] = t2_converted[v] or 0
-- if duplicates are not ignored --> count the value
if IGNORE_KEYS==flags then
t2_converted[v] = t2_converted[v]+1
end
end
table2 = t2_converted
end
-- compares the key--value pairs
for k,v in pairs(table1) do
if table2[k]~=v then return false end
end
return true
end
@Jochnickel
This is my best and shortest idea.
(You need table.copy
and table.length
for that.)
local STRICT, IGNORE_KEYS, IGNORE_KEYS_AND_DUPLICATES = 0,1,2
function table.compare(table1, table2, flags)
if "table"~=type(table1) then error("The 1st parameter of compare() is not a table.") end
if "table"~=type(table2) then error("The 2nd parameter of compare() is not a table.") end
if "number"~=type(flags) then error("The 3rd parameter of compare() is not a number.") end
-- compare keys
if flags==STRICT then
local table2_unique_keys = table.copy(table2)
for k, _ in pairs(table1) do
-- unique key to table1
if not table2[k] then return false end
-- this key is not unique for table2
table2_unique_keys[k] = nil
end
-- not removed keys are unique to table2
if table.length(table2_unique_keys)~=0 then return false end
-- converts the tables into value--count
else
local both_tables = {table1, table2}
-- convert tables into value--count
for i, t in pairs(both_tables) do
-- the converted table
local converted = {}
for k,v in pairs(t) do
-- new value
if not converted[v] then converted[v] = 0 end
-- add 1 if duplicates are not ignored
if flags~=IGNORE_KEYS_AND_DUPLICATES then
converted[v] = converted[v] + 1
end
end
-- overrides the table with the converted one
both_tables[i] = converted
end
end
-- compares the values
for k,v in pairs(t1) do
if table2[k]~=v then return false end
end
return true
end
@Jochnickel @GniLudio
STRICT, IGNORE_KEYS, IGNORE_KEYS_AND_DUPLICATES = 0,1,2
function table.compare(table1, table2, flags)
if "table"~=type(table1) then error("The 1st parameter of compare() is not a table.") end
if "table"~=type(table2) then error("The 2nd parameter of compare() is not a table.") end
if "number"~=type(flags) then error("The 3rd parameter of compare() is not a number.") end
-- compare keys
if flags==STRICT then
-- local table2_unique_keys = table.copy(table2)
-- for k1 in pairs(table1) do
-- -- unique key to table1
-- if nil==table2[k1] then return false end
-- -- this key is not unique for table2
-- table2_unique_keys[k1] = nil
-- end
-- -- not removed keys are unique to table2
-- if table.length(table2_unique_keys)~=0 then
-- return false
-- end
-- -- converts the tables into value--count
else
local both_tables = {table1, table2}
-- convert tables into value--count
for i, t in pairs(both_tables) do
-- the converted table
local converted = {}
for k,v in pairs(t) do
-- new value
if not converted[v] then converted[v] = 0 end
-- add 1 if duplicates are not ignored
if flags~=IGNORE_KEYS_AND_DUPLICATES then
converted[v] = converted[v] + 1
end
end
-- overrides the table with the converted one
both_tables[i] = converted
end
table1, table2 = both_tables[1], both_tables[2]
end
-- compares the values
for k,v in pairs(table1) do
if not (table2[k]==v) then return false end
end
for k,v in pairs(table2) do
if not (table1[k]==v) then return false end
end
return true
end
requires table.copy and table.length
tests = {
-- {table1, table2, flag, equals?}
-- EQUAL ARRAY
{{1,2,3} , {1,2,3} , STRICT , true},
{{2,3,1} , {2,3,1} , IGNORE_KEYS , true},
{{3,1,2} , {3,1,2} , IGNORE_KEYS_AND_DUPLICATES , true},
-- UNEQUAL ARRAY
{{1,2,3} , {7,5,1} , STRICT, false},
{{1,2,3} , {7,5,1} , IGNORE_KEYS, false},
{{1,2,3} , {7,5,1} , IGNORE_KEYS_AND_DUPLICATES, false},
-- EQUAL DICT
{{["cat"]="miau", ["dog"]="wuff"} , {["dog"]="wuff",["cat"]="miau"} , STRICT , true},
{{["cat"]="miau", ["dog"]="wuff"} , {["dog"]="wuff",["cat"]="miau"} , IGNORE_KEYS , true},
{{["cat"]="miau", ["dog"]="wuff"} , {["dog"]="wuff",["cat"]="miau"} , IGNORE_KEYS_AND_DUPLICATES , true},
-- UNEQUAL DICT
-- pair missing in table 2
{{["cat"]="miau", ["dog"]="wuff"} , {["dog"]="wuff"} , STRICT , false},
{{["cat"]="miau", ["dog"]="wuff"} , {["dog"]="wuff"} , IGNORE_KEYS , false},
{{["cat"]="miau", ["dog"]="wuff"} , {["dog"]="wuff"} , IGNORE_KEYS_AND_DUPLICATES , false},
-- pair missing in table 1
{{["dog"]="wuff"} , {["dog"]="wuff",["cat"]="miau"} , STRICT , false},
{{["dog"]="wuff"} , {["dog"]="wuff",["cat"]="miau"} , IGNORE_KEYS , false},
-- KEY IMPORTANT
{{["a"]="a",["b"]="b"},{["b"]="a",["a"]="b"},STRICT, false},
{{["a"]="a",["b"]="b"},{["b"]="a",["a"]="b"},IGNORE_KEYS, true},
{{["a"]="a",["b"]="b"},{["b"]="a",["a"]="b"},IGNORE_KEYS_AND_DUPLICATES, true},
-- UNEQUAL VALUE COUNT
{{["dog"]="dog",["cat"]="not dog", ["horse"]="not dog"},{["dog"]="dog", ["horse"]="not dog"}, STRICT, false},
{{["dog"]="dog",["cat"]="not dog", ["horse"]="not dog"},{["dog"]="dog", ["horse"]="not dog"}, IGNORE_KEYS, false},
{{["dog"]="dog",["cat"]="not dog", ["horse"]="not dog"},{["dog"]="dog", ["horse"]="not dog"}, IGNORE_KEYS_AND_DUPLICATES, true},
}
for i, test in pairs(tests) do t1,t2, flags, bool = test[1], test[2], test[3], test[4] print(bool==table.compare(t1,t2,flags)) end
did edit your comment be: :P
(not table2[k1])->(nil==table2[k1])
-- (not table2[k1])==(false==table2[k1])
-- edit: first part of code not necessary
@Jochnickel
STRICT
mode.
t = {
[{}] = "first pair",
[{}] = "second pair",
[{1,2,3}] = "third pair",
[{1,2,3}] = "fourth pair"
}
STRICT, IGNORE_KEYS, IGNORE_KEYS_AND_DUPLICATES = 0,1,2
function table.compare(table1, table2, flags)
if "table"~=type(table1) then error("The 1st parameter of compare() is not a table.") end
if "table"~=type(table2) then error("The 2nd parameter of compare() is not a table.") end
if "number"~=type(flags) then error("The 3rd parameter of compare() is not a number.") end
if flags~=STRICT then
local both_tables = {table1, table2}
for i, t in pairs(both_tables) do
local converted = {}
for k,v in pairs(t) do
if not converted[v] then converted[v] = 0 end
if flags~=IGNORE_KEYS_AND_DUPLICATES then
converted[v] = converted[v] + 1
end
end
both_tables[i] = converted
end
table1, table2 = both_tables[1], both_tables[2]
end
for t=0,1 do
for k,v in pairs(table1) do
v2 = table2[k]
if "table"==type(v) and "table"==type(v2) then
if not table.compare(v,v2,flags) then return false end
else if table2[k]~=v
then return false end
end
end
table1, table2 = table2, table1
end
return true
end
Compare Tables
What I want
It would be nice to have a function that compares two tables.
Problems
1) Comparing tables that include other tables. 2) Especially dictionaries are complicated.
My little Function
Not made for dictionaries