【问题标题】:Comparing tables in lua, where keys are tables比较lua中的表,其中键是表
【发布时间】:2018-03-26 19:03:24
【问题描述】:

我需要比较两个表是否相等 - 就像在相同的内容中一样。两个表都有表作为键。

例如:

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

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

【问题讨论】:

  • 这些表中的键不是表。
  • 您在编程时有什么问题?展示你的方法。
  • 如果key和value可以是任意结构体的话会很复杂。我想你可以自己设计一个结构体。

标签: lua


【解决方案1】:

我的解决方案不是绝对的(不喜欢键),但应该适用于您提出问题的嵌套表。我的概念是递归且简单的:

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

function compare (one, two)

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

                -- If both types are the same, both are tables and 
                -- the tables are the same size, recurse through each
                -- table entry.
                for loop=1, #one do
                    if compare (one[loop], two[loop]) == false then
                        return false
                    end
                end 

                -- All table contents match
                return true
            end
        else
            -- Values are not tables but matching types. Compare
            -- them and return if they match
            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

【讨论】:

    【解决方案2】:

    另一种方法是以shown in 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 {}       -- initial value
        output = output or {}     -- initial value
        if type(value) == "number" or type(value) == "string" then
            table.insert (output, name .. " = " .. basicSerialize(value))
        elseif type(value) == "table" then
            if saved[value] then    -- value already saved?
                table.insert (output, name .. " = " .. saved[value])  -- use its previous name
            else
                saved [value] = name   -- save name for next time
                table.insert (output, name .. " = {}")     -- create a new table
                for k,v in pairs(value) do      -- save its fields
                    local fieldname = string.format("%s[%s]", name, basicSerialize(k))
                    save (fieldname, v, saved, output)
                end
            end
        else
            error("cannot save a " .. 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
    

    【讨论】:

      【解决方案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
      

      欲了解更多信息,请参阅:https://web.archive.org/web/20131225070434/http://snippets.luacode.org/snippets/Deep_Comparison_of_Two_Values_3

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-11
        • 1970-01-01
        • 2021-04-03
        • 1970-01-01
        • 1970-01-01
        • 2017-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多