Lua:如何在表中查找键(或对象)

ako*_*e01 5 lua hashtable lua-table

我想存储一个lua表,其中键是其他lua表.我知道这是可能的但我希望能够使用这些表的副本在表中查找.具体来说,我希望能够做到:

t = {}
key = { a = "a" }
t[key] = 4
key2 = { a = "a" }
Run Code Online (Sandbox Code Playgroud)

然后我希望能够查找:

t[key2]
Run Code Online (Sandbox Code Playgroud)

得到4.

我知道我可以key变成一个字符串并将其放入表格中t.我还考虑过编写自定义哈希函数或者通过嵌套表来实现这一点.有没有最好的方法让我获得这种功能?我还有其他选择吗?

kik*_*ito 6

在Lua中,分别创建的两个表被认为是"不同的".但是如果你创建一个表,你可以将它分配给你想要的任何变量,当你比较它们时,Lua会告诉你它们是平等的.换一种说法:

t = {}
key = { a = "a" }
t[key] = 4
key2 = key
...
t[key2] -- returns 4
Run Code Online (Sandbox Code Playgroud)

所以,这就是做你想做的简单,干净的方式.存储在key某处,以便您可以4使用它来检索背面.这也很快.

如果你真的不想这样做......那么,有一种方法.但它有点低效和丑陋.

第一部分是创建一个比较两个单独表的函数.如果两个表是"等价的",它应该返回true,否则返回false.我们称之为等价物.它应该像这样工作:

equivalent({a=1},{a=1})          -- true
equivalent({a=1,b=2}, {a=1})     -- false
equivalent({a={b=1}}, {a={b=2}}) -- false
Run Code Online (Sandbox Code Playgroud)

该函数必须是递归的,以处理包含表本身的表.如果其中一个表"包含"另一个表但具有更多元素,也不能被愚弄.我出来了这个实现; 可能那里有更好的.

local function equivalent(a,b)
  if type(a) ~= 'table' then return a == b end

  local counta, countb = 0, 0

  for k,va in pairs(a) do
    if not equivalent(va, b[k]) then return false end
    counta = counta + 1
  end

  for _,_ in pairs(b) do countb = countb + 1 end

  return counta == countb
end
Run Code Online (Sandbox Code Playgroud)

我不打算在这里解释这个功能.我希望它能够清楚地表明它的作用.

该难题的另一部分在于比较键时t使用该equivalent功能.这可以通过仔细的元表操作和额外的"存储"表来完成.

我们基本上t变成了冒名顶替者.当我们的代码告诉它在键下存储一个值时,它不会将它保存在自身中; 相反,它给了额外的表(我们称之为store).当代码请求t一个值时,它会搜索它store,但是使用该equivalent函数来获取它.

这是代码:

local function equivalent(a,b)
... -- same code as before
end

local store = {} -- this is the table that stores the values

t = setmetatable({}, {
  __newindex = store,
  __index = function(tbl, key)
    for k,v in pairs(store) do
      if equivalent(k,key) then return v end
    end
  end
})
Run Code Online (Sandbox Code Playgroud)

用法示例:

t[{a = 1}] = 4

print(t[{a = 1}]) -- 4
print(t[{a = 1, b = 2}]) -- nil
Run Code Online (Sandbox Code Playgroud)