算法 – 如何深入比较2个Lua表,这些表可能有也可能没有表作为键
发布时间:2020-12-15 00:16:09 所属栏目:大数据 来源:网络整理
导读:(也发布在Lua邮件列表上) 所以我一直在编写深度复制算法,我想测试它们是否按照我希望的方式工作.虽然我可以访问原始复制映射,但我想要一个通用的深度比较算法,它必须能够比较表键(表作为键?). 我的深拷贝算法在这里是可用的:https://gist.github.com/SoniE
(也发布在Lua邮件列表上)
所以我一直在编写深度复制算法,我想测试它们是否按照我希望的方式工作.虽然我可以访问原始>复制映射,但我想要一个通用的深度比较算法,它必须能够比较表键(表作为键?). 我的深拷贝算法在这里是可用的:https://gist.github.com/SoniEx2/fc5d3614614e4e3fe131(它不是很有组织,但有3个,一个使用递归调用,另一个使用todo表,另一个模拟调用栈(非常难看)但5.1兼容的方式)) 递归版: local function deep(inp,copies) if type(inp) ~= "table" then return inp end local out = {} copies = (type(copies) == "table") and copies or {} copies[inp] = out -- use normal assignment so we use copies' metatable (if any) for key,value in next,inp do -- skip metatables by using next directly -- we want a copy of the key and the value -- if one is not available on the copies table,we have to make one -- we can't do normal assignment here because metatabled copies tables might set metatables -- out[copies[key] or deep(key,copies)]=copies[value] or deep(value,copies) rawset(out,copies[key] or deep(key,copies),copies[value] or deep(value,copies)) end return out end 编辑:我发现这样的东西并没有真正处理表作为键:http://snippets.luacode.org/snippets/Deep_Comparison_of_Two_Values_3(下面的代码片段的副本) 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 序列化也不是一种选择,因为序列化的顺序是“随机的”. 解决方法
正如其他人所说,这在很大程度上取决于你对等价的定义.
如果你想要这是真的: local t1 = {[{}] = {1},[{}] = {2}} local t2 = {[{}] = {1},[{}] = {2}} assert( table_eq(t1,t2) ) 如果你这样做,那么每当t1中的键是一个表时,你就必须这样做 function table_eq(table1,table2) local avoid_loops = {} local function recurse(t1,t2) -- compare value types if type(t1) ~= type(t2) then return false end -- Base case: compare simple values if type(t1) ~= "table" then return t1 == t2 end -- Now,on to tables. -- First,let's avoid looping forever. if avoid_loops[t1] then return avoid_loops[t1] == t2 end avoid_loops[t1] = t2 -- Copy keys from t2 local t2keys = {} local t2tablekeys = {} for k,_ in pairs(t2) do if type(k) == "table" then table.insert(t2tablekeys,k) end t2keys[k] = true end -- Let's iterate keys from t1 for k1,v1 in pairs(t1) do local v2 = t2[k1] if type(k1) == "table" then -- if key is a table,we need to find an equivalent one. local ok = false for i,tk in ipairs(t2tablekeys) do if table_eq(k1,tk) and recurse(v1,t2[tk]) then table.remove(t2tablekeys,i) t2keys[tk] = nil ok = true break end end if not ok then return false end else -- t1 has a key which t2 doesn't have,fail. if v2 == nil then return false end t2keys[k1] = nil if not recurse(v1,v2) then return false end end end -- if t2 has a key which t1 doesn't have,fail. if next(t2keys) then return false end return true end return recurse(table1,table2) end assert( table_eq({},{}) ) assert( table_eq({1,2,3},{1,3}) ) assert( table_eq({1,3,foo = "fighters"},{["foo"] = "fighters",1,3}) ) assert( table_eq({{{}}},{{{}}}) ) assert( table_eq({[{}] = {1},[{}] = {2}},{[{}] = {1},[{}] = {2}}) ) assert( table_eq({a = 1,[{}] = {}},{[{}] = {},a = 1}) ) assert( table_eq({a = 1,[{}] = {1},{[{}] = {2},a = 1,[{}] = {1}}) ) assert( not table_eq({1,4},3}) ) assert( not table_eq({1,{["foo"] = "bar",3}) ) assert( not table_eq({{{}}},{{{{}}}}) ) assert( not table_eq({[{}] = {1},[{}] = {2},[{}] = {3}}) ) assert( not table_eq({[{}] = {1},[{}] = {3}}) ) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |