使用表格的内容作为关键字

时间:2011-05-26 13:55:02

标签: lua

是否有一种简单的方法可以创建类似字典的集合,即

  1. 表可以用作键
  2. 具有相同内容的表被视为等效(而不是默认指针比较)
  3. e.g。之后

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

    t[k2]应评估为true t本身也应该以相同的方式用作关键字。

    如果没有

    ,有没有办法做到这一点
    1. 重新实现哈希表
    2. k1k2转换为字符串? (这就是我目前正在做的事情。)

5 个答案:

答案 0 :(得分:4)

将两个表序列化为字符串是解决方案Roberto Ierusalimschy(Lua的首席架构师)建议按照Lua第二版编程中的内容进行索引

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

答案 1 :(得分:3)

如果要用作键的表是固定的并且其内容不会更改,则可以在{em> newindex 元方法中为t按需构建SHA2摘要,并使用摘要作为真正的关键。摘要将缓存在由真实表索引的另一个表中。

答案 2 :(得分:1)

您可以在两个表的元表中实现和设置__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")

比较可以更快地实现,因为现在常见的条目被检查两次,但是你明白了。

我无法评论性能,因为它确实使用了metatable查找,并且需要遍历每个比较或赋值的所有表,但是因为您不想散列表或将它们转换为字符串(aka序列化他们)这是唯一的方法。如果我是你,我会认真考虑检查表的序列化,而不是上面的方法。

答案 3 :(得分:0)

This(“键是引用”部分)表示键是对象的引用,因此使用与示例中相同的表将不起作用。我认为你目前的做法可能是最好的方式,但我可能是错的。

答案 4 :(得分:0)

如果您可以使用库依赖项,则可以使用类似Penlight的内容,它似乎提供了集http://penlight.luaforge.net/#T10