【问题标题】:Determine if two tables have the same set of keys确定两个表是否具有相同的键集
【发布时间】:2013-02-23 07:33:41
【问题描述】:

我通过将集合的值放在表键中并将1 作为表值来使用 Lua 表作为集合,例如

function addToSet(s,...)      for _,e in ipairs{...} do s[e]=1   end end
function removeFromSet(s,...) for _,e in ipairs{...} do s[e]=nil end end

local logics = {}
addToSet(logics,true,false,"maybe")

要测试两组是否相等,我需要确保它们具有完全相同的键。有什么有效的方法来做到这一点?

【问题讨论】:

    标签: performance lua set


    【解决方案1】:

    既然您询问了效率,我将提供一个替代实现。根据您预期的输入表,您可能希望避免第二个循环的查找。如果期望表相同,则效率更高,如果存在差异,则效率较低。

    function sameKeys(t1,t2)
      local count=0
      for k,_ in pairs(t1) do
        if t2[k]==nil then return false end
        count = count + 1
      end
      for _ in pairs(t2) do
        count = count - 1
      end
      return count == 0
    end
    

    除非必要,否则另一个版本会避免查找。这在另一组用例中可能会执行得更快。

    function sameKeys(t1,t2)
      local count=0
      for _ in pairs(t1) do count = count + 1 end
      for _ in pairs(t2) do count = count - 1 end
      if count ~= 0 then return false end
      for k,_ in pairs(t1) do if t2[k]==nil then return false end end
      return true
    end
    

    编辑:经过更多的研究和测试,我得出的结论是您需要区分 Lua 和 LuaJIT。使用 Lua,性能特征由 Lua 的 Parser 决定,因此由源代码令牌的数量决定。对于 Lua,这意味着 Phrogz 的版本很可能是更快的选择。对于 LuaJIT,情况发生了巨大变化,因为解析器不再是问题。对于几乎所有情况,我展示的第一个版本是一个改进,当表非常大时,第二个版本可能是最好的。我建议每个人都运行自己的基准测试并检查哪个版本在他们的环境中效果最好。

    【讨论】:

    • 另外,如果查找是最昂贵的部分,您可以首先进行“仅计数”检查,并且只有当键的数量匹配时,才比较键本身。在任何情况下,您都希望根据您的实际数据对不同的备选方案进行基准测试。
    • 在 Lua 中查找的成本不会增加或减少。
    • 在使用一组特定的集合进行测试时,上述解决方案最终分别比接受的答案慢大约 1.5 倍和 2 倍。好主意,但最终既不简单也不高效。
    • 我用 LuaJIT 测试了它(我们说的是性能,对吗?),并且在一些测试集上,我的第二个版本比你的版本快 10 倍。正如我所说:这取决于您拥有的用例。
    【解决方案2】:

    遍历两个表并确保键在另一个中具有值。发现不匹配时立即失败,如果您通过了两者,则返回 true。对于 MN 大小的集合,这是 O(M+N) 复杂度。

    function sameKeys(t1,t2)
      for k,_ in pairs(t1) do if t2[k]==nil then return false end end
      for k,_ in pairs(t2) do if t1[k]==nil then return false end end
      return true
    end
    

    实际操作:

    local a,b,c,d = {},{},{},{}
    addToSet(a,1,2,3)
    addToSet(b,3,1,2,3,3,1)
    addToSet(c,1,2)
    addToSet(d,2,1)
    print(sameKeys(a,b)) --> true
    print(sameKeys(a,c)) --> false
    print(sameKeys(d,c)) --> true
    

    注意测试 t[k]==nil 比仅仅测试 not t[k] 来处理(不太可能)您为表条目设置值 false 并且您希望键出现在设置。

    【讨论】:

    • false 是表中的有效值,if not t2[k] 会错过它。
    • @finnw 是的。从“注意”开始,请参阅我的答案部分。它不仅不适用于问题,而且还由答案处理。
    • 是的,但它是一个脚注,第一个版本比第二个版本没有优势,为什么不只使用第二个?
    • @finnw 公平点;性能是一样的,省了两个字不值。已编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多