Lua 中比较具有表作为键的表格

我需要比较两个表格是否相等-即具有相同的内容。两个表格都具有表格键。

例如:

t1 = {{1,1},{2,2}}
t2 = {{1,1},{2,2}}
t3 = {{1,1},{2,2},{3,3}}

t1 和 t2 应该相等,但是 t1 和 t3 应该不相等。

点赞
用户2705567
用户2705567

我的解决方案并非绝对(不使用键),但应该适用于你提出的嵌套表。我的概念是递归和简单的:

从每个输入中取一个条目,确保它们:类型匹配,都是表格,并且两个表格具有相同的长度。如果这三件事都成立,那么现在可以递归地1:1比较这两个表格。如果类型不匹配或表格长度不同,则会自动失败。

function compare (one, two)

    if type(one) == type(two) then
        if type(one) == "table" then
            if #one == #two then

                -- 如果两种类型相同,都是表格且表格大小相同,则递归遍历每个表格条目。
                for loop=1, #one do
                    if compare (one[loop], two[loop]) == false then
                        return false
                    end
                end

                -- 所有表内容都匹配
                return true
            end
        else
            -- 值不是表格但类型匹配。比较它们并返回它们是否匹配
            return one == two
        end
    end
    return false
end

do
    t1 = {{1,1},{2,2}}
    t2 = {{1,1},{2,2}}
    t3 = {{1,1},{2,2},{3,3}}

    print (string.format(
        "t1 == t2 : %s",
        tostring(compare (t1,t2))))

    print (string.format(
        "t1 == t3 : %s",
        tostring(compare (t1,t3))))
end

输出是:

t1 == t2 : true
t1 == t3 : false
2017-10-17 04:06:47
用户736889
用户736889

另一种方法是按照 Programming in Lua 所示的方式序列化两个表。这将生成一个字符串集合的输出,当运行时,它们会重新创建表。将序列化器的输出存储在一个表中,而不是输出它们进行比较。

一旦两个表都序列化为字符串集合,比较表 A 的所有行与表 B 的所有行,并消除它们之间的任何重复将变得简单。如果在处理表 A 结束时,在表 A 或表 B 中有任何行剩余,则它们不相等。

将表序列化为字符串表的代码(修改自 PIL),并比较两个表 a 和 b:

function basicSerialize (o)
    if type(o) == "number" then
      return tostring(o)
    else   -- assume it is a string
      return string.format("%q", o)
    end
end

function save (name, value, saved, output)
    saved = saved or {}       -- 初始值
    output = output or {}     -- 初始值
    if type(value) == "number" or type(value) == "string" then
        table.insert (output, name .. " = " .. basicSerialize(value))
    elseif type(value) == "table" then
        if saved[value] then    -- 已保存该值?
            table.insert (output, name .. " = " .. saved[value])  -- 使用它的先前名称
        else
            saved [value] = name   -- 保存名称以供下一次使用
            table.insert (output, name .. " = {}")     -- 创建一个新表
            for k,v in pairs(value) do      -- 保存其字段
                local fieldname = string.format("%s[%s]", name, basicSerialize(k))
                save (fieldname, v, saved, output)
            end
        end
    else
        error("不能保存类型为 " .. type(value) .. " 的值")
    end
    return output
end

function compareSerializedTable (t1, t2)
    if (#t1 ~= #t2) then
        return false
    end

    for i = #t1, 1, -1 do
        local line = t1 [i]
        for k, comp in ipairs (t2) do
            if (line == comp) then
                table.remove (t1, i)
                table.remove (t2, k)
                break
            end
        end
    end

    return (#t1 == 0 and #t2 == 0)
end

t1 = {{1,1},{2,2}}
t2 = {{1,1},{2,2}}
t3 = {{1,1},{2,2},{3,3}}

o1 = save ('t', t1)
o2 = save ('t', t2)
o3 = save ('t', t3)

print (compareSerializedTable (o1, o2)) --true
print (compareSerializedTable (o1, o3)) --false
2018-01-19 21:05:57
用户4446971
用户4446971

你需要的是一个表格比较函数。由于有许多不同的实现,因此这不是语言的内置函数。

一个常见的实现是深度比较。下面的函数将深度比较表格,它有第三个参数来忽略元表或不忽略。

function deepcompare(t1, t2, ignore_mt)
    local ty1 = type(t1)
    local ty2 = type(t2)
    if ty1 ~= ty2 then
        return false
    end
    -- 非表格类型可以直接比较
    if ty1 ~= "table" and ty2 ~= "table" then
        return t1 == t2
    end
    -- 同样可以比较具有 __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

更多信息请参见: https://web.archive.org/web/20131225070434/http://snippets.luacode.org/snippets/Deep_Comparison_of_Two_Values_3

2020-04-09 09:57:06