将表格的内容用作关键词。

有没有一种简单的方法来创建类似于字典的集合,即:

  1. 表格可用作键
  2. 具有相同内容的表格被视为等效(而不是默认指针比较)

例如,在

t = createCustomTable()
k1 = {'a''b''c'}
k2 = {'a''b''c'}
t [k1] = true

t [k2] 应该计算为 true

此外,t 本身应该以相同的方式用作键。

是否有方法可以做到这一点,而不必

  1. 重新实现哈希表
  2. k1k2 转换为字符串? (这是我目前正在做的。)

原文链接 https://stackoverflow.com/questions/6139684

点赞
stackoverflow用户513763
stackoverflow用户513763

你可以在两个表的元表中实现并设置 __eq 方法。

k1 = {'a','b','c'}
k2 = {'a','b','c'}
mt1={__eq=function(a,b)
   for k,v in pairs(a) do
      if b[k]~=v then return false end
   end
   for k,v in pairs(b) do
      if a[k]~=v then return false end
   end
   return true
end
}
setmetatable(k1,mt1)
setmetatable(k2,mt1)

assert(k1==k2,"Table comparison failed")

function newDict(orig)
    if orig then
        return orig
    else
        local mt2={}
        local lookup ={} -- lookup table as upvalue to the metamethods
        mt2.__newindex = function(t,k,v) -- Registering a new table
            if type(k)~="table" then return end
            if v then   -- v ~= false
                local found
                for idx,val in pairs(lookup) do
                    if k==val then
                        found=1
                        break
                    end -- If already seen, skip.
                end
                if not found then
                    lookup[#lookup+1]=k -- not seen before, add
                end
            else -- v == false or nil
                local to_erase
                for idx,val in pairs(lookup) do -- Assume there is only one match in the dict.
                    if k==val then
                        lookup[k]=nil
                        break
                    end --don't continue after this, next will be confused.
                end
            end
        end

        mt2.__index = function(t,k) -- looking up a table
            for idx,val in pairs(lookup) do
                if k==val then
                    return true
                end
            end
            return false
        end
        return setmetatable({},mt2)
    end
end

t1 = newDict()
t2 = newDict()

k1={1,2,3}
k2={"a"}
k3={"z","d","f"}

k1b={1,2,3}
k2b={"a"}
k3b={"z","d","f"}

setmetatable(k1,mt1)
setmetatable(k2,mt1)
setmetatable(k3,mt1)

setmetatable(k1b,mt1)
setmetatable(k2b,mt1)
setmetatable(k3b,mt1)

-- Test multiple entries in 1 dict
t1[k1]=true
t1[k2]=true
assert(t1[k1b],"t1[k1b] did not return true")
assert(t1[k2b],"t1[k2b] did not return true")
-- Test confusion between 2 dicts
t2[k3]=true
assert(not t1[k3b],"t1[k3b] did return true")
assert(not t2[k1b],"t2[k1b] did return true")

现在可以更快地实现比较,因为现在共同条目只被检查了两次,但你明白我的意思。

由于它严重依赖元表查找,并在每次比较或赋值时需要遍历所有表,因此我无法对其性能进行评论,但由于不想对表进行哈希处理或将它们转换为字符串(又称序列化它们),所以这是唯一的方法。如果我是你,我会认真考虑检查表的序列化而不是采用上述方法。

2011-05-26 14:05:50
stackoverflow用户597564
stackoverflow用户597564

这个链接("Keys are references" 部分) 表示键是对象的引用,因此在您提供的示例中使用相同的表是行不通的。我认为您目前所做的方式可能是最好的方式,但我可能错了。

2011-05-26 14:42:44
stackoverflow用户206020
stackoverflow用户206020

如果你可以接受一个依赖于库的话,你可以使用像Pentlight这样的东西,它似乎提供了setshttp://penlight.luaforge.net/#T10

2011-05-26 20:03:24
stackoverflow用户107090
stackoverflow用户107090

如果要将表作为键,并且其内容不会更改,您可以在 tnewindex 元方法中按需构建一个 SHA2 摘要,并将摘要用作实际键。该摘要将被缓存在另一个以真实表为索引的表中。

2011-05-26 22:33:02
stackoverflow用户34799
stackoverflow用户34799

在《Lua 程序设计》第二版中,Lua 的首席架构师 Roberto Ierusalimschy 建议将这两个表序列化为字符串来进行内容索引。

如果你的所有关键表都是字符串数组(没有嵌入的空值),那么可以使用 table.concat(t,'\0') 快速完成此操作。(显然,如果你想要与索引无关的标识符,则需要对表进行 排序。)

2011-05-27 01:41:06