返回Lua中表的索引

时间:2012-03-21 03:37:27

标签: indexing lua

我已经问了好几个人并搜索了谷歌,但还是没有找到答案;有没有办法在Lua中返回表中变量的索引?我有一个回调函数,它返回一个永远是表的一部分的变量。在回调中,它只是被称为" shape_one",但形状本身将是一个形状表,如下所示:Objects.shapes [4]。

如果" shape_one"具有Objects.shapes [4]的值,那么有没有办法返回4?

我希望我足够清楚。

3 个答案:

答案 0 :(得分:3)

这是你的情况吗?

local shapes = { }

local function callback(shape_one)
  -- ???
end

local the_shape = { is_circle = false }

shapes[4] = the_shape

assert(callback(the_shape) == 4)

shapes[4]the_shape都包含对值的引用,但在Lua中,这两个变量之间没有其他连接。所以,你不能说“表中变量的索引”,你应该说“表中值的索引,匹配变量中的值”。 “匹配”的确切取决于您的情况。在这种情况下,您最有可能寻找引用相等。

请注意,在Lua中,所有表值都是唯一的,因此the_shape ~= { is_circle = false }(即具有相同内容的新表),但是the_shape == shapes[4](两者都指向相同的值)。如果需要,您可以按值比较表,但这是一个单独的主题。

所以,如果你真的想在表中找到值的索引,你必须手动搜索它。要么进行线性搜索:

local function callback(shape_one)
  for k, v in pairs(shapes) do
    if v == shape_one then
      return k
    end
  end
  return nil, "shape not found" -- or maybe call error() here
end

...或缓存所有形状:

local function tflip(t)
 local r = { }
 for k, v in pairs(t) do
   r[v] = k -- overrides duplicate values if any
 end
 return r
end

local shape_index = tflip(shapes)

local function callback(shape_one)
 return shape_index[shape_one] -- will return nil if not found
end

请注意,shape_index当然会阻止其内容的垃圾收集。假设它的生命周期与shapes表的生命周期相同并且与它保持同步,这不是问题。如果不是这种情况,您可以将shapes表配置为弱键。 (如果你想让我扩展这一点,请告诉我。)

顺便说一下,你可以通过一些可以表达的魔法自动保持shape_index的最新状态。告诉我,如果你想解释这个,我会更新答案。

答案 1 :(得分:1)

最有效的方法是使用shape_one作为关键:

local shapes = { }

local function callback(shape)
    -- if you wanted to remove shape_one from the table:
    shapes[shape] = nil
    -- or if you want verify it's in there:
    print(shapes[shape] ~= nil)
end

local the_shape = { is_circle = false }

shapes[the_shape] = true

callback(the_shape)

for shape, _ in pairs(shapes) do
    callback(shape)
end

Lua使用散列来确保每个表都是一个唯一的密钥,它使用的算法非常快(不像在Alexander Gladysh的解决方案中那样遍历表)。

答案 2 :(得分:0)

我知道它用于别的东西,但它也适用于这种情况。

shapes = {} -- Create your table, can be called anything
shapes.r_index = {} -- Holds the number value, i.e. t[1] = 'Foo'
shapes.r_table = {} -- Holds the string value, i.e. t['Foo'] = 1

mt = {} -- Create the metatable
mt.__newindex = function (self, key, value) -- For creating the new indexes
    if value == nil then -- If you're trying to delete an entry then
        if tonumber(key) then -- Check if you are giving a numerical index
            local i_value = self.r_index[key] -- get the corrosponding string index
            self.r_index[key] = nil -- Delete
            self.r_table[i_value] = nil
        else -- Otherwise do the same as above, but for a given string index
            local t_value = self.r_table[key]
            self.r_index[t_value] = nil
            self.r_table[key] = nil
        end
    else
        table.insert(self.r_index, tonumber(key), value) -- For t[1] = 'Foo'
        self.r_table[value] = key -- For t['Foo'] = 1
    end
end
mt.__index = function (self, key) -- Gives you the values back when you index them
    if tonumber(key) then
        return (self.r_index[key]) -- For For t[1] = 'Foo'
    else
        return (self.r_table[key]) -- For t['Foo'] = 1
    end
end

setmetatable(shapes, mt) -- Creates the metatable

shapes[1] = "Circle" -- Set the values
shapes[2] = "Square"

print(shapes[1], shapes[2]) -- And *should* proove that it works
print(shapes['Circle'], shapes['Square'])

shapes[1] = nil
print(shapes[1], shapes[2]) -- And *should* proove that it works
print(shapes['Circle'], shapes['Square'])

有了这个,你应该能够访问和修改这些值。它使用数字索引,因此如果不是您想要的那样,您可能需要更改该位。这将允许您使用一个变量创建新键并获取值;然而,它可能不是最有效的实现。