检查Lua表成员是否存在于任何级别

时间:2015-06-07 01:31:47

标签: lua lua-table

我需要检查一个成员是否存在于不在下一级别的表中,而是存在于成员的路径中。

foo = {}
if foo.bar.joe then
  print(foo.bar.joe)
end

这会投射attempt to index field 'bar' (a nil value),因为未定义条形码。

我通常的解决方案是逐个测试链条。

foo = {}
if foo.bar and foo.bar.joe then
  print(foo.bar.joe)
end

但是当有许多嵌套表时,这可能非常繁琐。有没有更好的方法来进行这项测试而不是逐件?

6 个答案:

答案 0 :(得分:2)

我不明白你所说的“沿着成员之路”是什么意思。从这个例子中,我假设你试图在“子表”中找到一个值?

local function search(master, target) --target is a string
    for k,v in next, master do
        if type(v)=="table" and v[target] then return true end
    end
end

一个简单的例子。如果您使用此类函数,则可以传递foo表和joe字符串以查看是否存在foo.*.joe。希望这会有所帮助。

答案 1 :(得分:2)

debug.setmetatable(nil, {__index = {}})

foo = {}
print(foo.bar.baz.quux)
print(({}).prd.krt.skrz.drn.zprv.zhlt.hrst.zrn)  -- sorry ))

答案 2 :(得分:1)

如果我理解你的问题,这是一种可能性:

function isField(s)
  local t
  for key in s:gmatch('[^.]+') do
    if t == nil then
      if _ENV[ key ] == nil then return false end
      t = _ENV[ key ]
    else
      if t[ key ] == nil then return false end
      t = t[ key ]
    end
    --print(key) --for DEBUGGING
  end
  return true
end

-- To test

t = {}
t.a = {}
t.a.b = {}
t.a.b.c = 'Found me'

if isField('t.a.b.c') then print(t.a.b.c) else print 'NOT FOUND' end
if isField('t.a.b.c.d') then print(t.a.b.c.d) else print 'NOT FOUND' end

更新:根据cauterite的建议,这里有一个版本,也适用于当地人,但必须采取两个参数:(

function isField(t,s)
  if t == nil then return false end
  local t = t
  for key in s:gmatch('[^.]+') do
    if t[ key ] == nil then return false end
    t = t[ key ]
  end
  return true
end

-- To test

local
t = {}
t.a = {}
t.a.b = {}
t.a.b.c = 'Found me'

if isField(t,'a.b.c') then print(t.a.b.c) else print 'NOT FOUND' end
if isField(t,'a.b.c.d') then print(t.a.b.c.d) else print 'NOT FOUND' end

答案 3 :(得分:1)

foo = {}

foo.boo = {}

foo.boo.jeo = {}

foo.boo.joe是foo [' boo'] [' joe']等等

我做下一个功能

function exist(t)

    local words = {}
    local command

    for i,v in string.gmatch(t, '%w+') do words[#words+1] = i end

    command = string.format('a = %s', words[1])

    loadstring(command)()

    if a == nil then return false end

    for count=2, #words do
        a = a[words[count]]
        if a == nil then return false end
    end

    a = nil
    return true
end

foo = {}
foo.boo = {}
foo.boo.joe = {}

print(exist('foo.boo.joe.b.a'))

使用loadstring创建临时变量。我的lua ver是5.1

在5.2 5.3中删除loadstring,而不是使用load

答案 4 :(得分:1)

要搜索表格任何级别的元素,我会使用这样的方法:

function exists(tab, element)
    local v
    for _, v in pairs(tab) do
        if v == element then
            return true
        elseif type(v) == "table" then
            return exists(v, element)
        end
    end
    return false
end

testTable = {{"Carrot", {"Mushroom", "Lettuce"}, "Mayonnaise"}, "Cinnamon"}
print(exists(testTable, "Mushroom")) -- true
print(exists(testTable, "Apple")) -- false
print(exists(testTable, "Cinnamon")) -- true

答案 5 :(得分:0)

我认为你正在寻找这些方面的东西:

local function get(Obj, Field, ...)
    if Obj == nil or Field == nil then
        return Obj
    else
        return get(Obj[Field], ...)
    end
end

local foo = {x = {y = 7}}
assert(get() == nil)
assert(get(foo) == foo)
assert(get(foo, "x") == foo.x)
assert(get(foo, "x", "y") == 7)
assert(get(foo, "x", "z") == nil)
assert(get(foo, "bar", "joe") == nil)
assert(get(foo, "x", "y") or 41 == 7)
assert(get(foo, "bar", "joe") or 41 == 41)
local Path = {foo, "x", "y"}
assert(get(table.unpack(Path)) == 7)

get只是遍历给定的路径,直到遇到nil。似乎做了这个工作。尽管如此,请随意想出一个比“得到”更好的名字。

与往常一样,在与or结合使用时要小心。

我对Egor的聪明回答印象深刻,但总的来说我认为我们不应该依赖这样的黑客攻击。

另见