我想在Lua中检查两个表格是否具有相同的值,但没有找到方法。
我使用运算符==
,它似乎只检查相同的对象,而不是表格中的元素。
如果我有两个表格,
a={}
b={}
a==b
的值为false
。
但是如果
a={}
b=a
a==b
的值为true
。
我想知道在Lua中是否有一种方法可以检查两个表是否具有相同的元素。是否有像table.equals()
这样的内置函数进行检查?
我为Rutrus的解决方案提供一些改进。
---@param o1 any|table First object to compare
---@param o2 any|table Second object to compare
---@param ignore_mt boolean True to ignore metatables (a recursive function to tests tables inside tables)
function equals(o1, o2, ignore_mt)
if o1 == o2 then return true end
local o1Type = type(o1)
local o2Type = type(o2)
if o1Type ~= o2Type then return false end
if o1Type ~= 'table' then return false end
if not ignore_mt then
local mt1 = getmetatable(o1)
if mt1 and mt1.__eq then
--compare using built in method
return o1 == o2
end
end
local keySet = {}
for key1, value1 in pairs(o1) do
local value2 = o2[key1]
if value2 == nil or equals(value1, value2, ignore_mt) == false then
return false
end
keySet[key1] = true
end
for key2, _ in pairs(o2) do
if not keySet[key2] then return false end
end
return true
end
local function internalProtectedEquals(o1, o2, ignore_mt, callList)
if o1 == o2 then return true end
local o1Type = type(o1)
local o2Type = type(o2)
if o1Type ~= o2Type then return false end
if o1Type ~= 'table' then return false end
-- add only when objects are tables, cache results
local oComparisons = callList[o1]
if not oComparisons then
oComparisons = {}
callList[o1] = oComparisons
end
-- false means that comparison is in progress
oComparisons[o2] = false
if not ignore_mt then
local mt1 = getmetatable(o1)
if mt1 and mt1.__eq then
--compare using built in method
return o1 == o2
end
end
local keySet = {}
for key1, value1 in pairs(o1) do
local value2 = o2[key1]
if value2 == nil then return false end
local vComparisons = callList[value1]
if not vComparisons or vComparisons[value2] == nil then
if not internalProtectedEquals(value1, value2, ignore_mt, callList) then
return false
end
end
keySet[key1] = true
end
for key2, _ in pairs(o2) do
if not keySet[key2] then
return false
end
end
-- comparison finished - objects are equal do not compare again
oComparisons[o2] = true
return true
end
function pequals(o1, o2, ignore_mt)
return internalProtectedEquals(o1, o2, ignore_mt, {})
end
另外,您可以分析lua wiki上的CompareTables。
没有内置函数可以比较表格内容。
你需要编写自己的函数。你需要决定是浅层次还是深层次地比较表格的内容。 请参阅https://web.archive.org/web/20131225070434/http://snippets.luacode.org/snippets/Deep_Comparison_of_Two_Values_3以获取一些想法。
function do_tables_match( a, b )
return table.concat(a) == table.concat(b)
end
function is_table_empty( table_to_test )
-- Doesn't work
return table_to_test == {}
-- Works only if the table is numeric keyed with no gaps
return #table_to_test = 0
-- Works!
return next( table_to_test ) ~= nil
end
顺便提一下,我检查了@lhf的链接发现它已经失效了,我找到了这个有用的例子:
function is_table_equal(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 is_table_equal(v1,v2) then return false end
end
for k2,v2 in pairs(t2) do
local v1 = t1[k2]
if v1 == nil or not is_table_equal(v1,v2) then return false end
end
return true
end
我目前使用这个
local tableCompare
do
local compare
compare = function(src, tmp, _reverse)
if (type(src) ~= "table" or type(tmp) ~= "table") then
return src == tmp
end
for k, v in next, src do
if type(v) == "table" then
if type(tmp[k]) ~= "table" or not compare(v, tmp[k]) then
return false
end
else
if tmp[k] ~= v then
return false
end
end
end
return _reverse and true or compare(tmp, src, true)
end
tableCompare = function(src, tmp, checkMeta)
return compare(src, tmp) and (not checkMeta or compare(getmetatable(src), getmetatable(tmp)))
end
end
print(tableCompare({ 1 , b = 30 }, { b = 30, 1 }, false))
a.test=true
,那么b.test将保持不变。 - Ivo