我刚刚开始编程并选择了lua来编写处理XML配置文件的脚本。
我使用LuaXML(C绑定版本)加载XML文件,该文件将其映射到一个重度嵌套的表。
当我尝试编写一个函数来查找xmltable中标记的所有匹配项时,我的问题出现了。匹配项将插入到函数返回的表中。我的问题是这个表变量的声明,它必须是函数的本地变量。
首先我尝试了:
local result = result or {}
但是这会在每次递归时声明变量。
最后我提出了这个有效的解决方案,但对我来说似乎太复杂了:
function findall_wrapper(xmltable, tag)
local results = {}
function findall(xmltable, tag)
if xml.TAG == tag then table.insert (results, xmltable) end
for k, v in pairs(xmltable) do
if (type(v) == "table") then findall(v, tag) end
end
end
findall(xmltable, tag)
return results
end
如何以更好,更优雅的方式解决这个问题?
为什么local result = result or {}
在每次递归时声明变量?
很抱歉,如果我的问题的答案太明显,但正如我所提到的,我刚刚开始编程。
答案 0 :(得分:4)
实际上我觉得你已经想出了一个漂亮而优雅的解决方案。你正在做的是利用Lua中的函数closures,这在编写递归函数时非常有用,它需要在运行时构建数据结构。要使其完美,您需要做的就是在function findall
内function findall_wrapper
前添加local关键字,然后您的帮助函数将是本地的,并且不会污染全局命名空间。
详细说明一下:
有两种不同类型的函数,简单的递归函数和复杂的递归函数。所有递归函数都可以通过以下方式实现:
function sum_list(l)
if #l == 0 then
return 0
else
local e = table.remove(l)
return e + sum_list(l)
end
end
print(sum_list({1,2,3,4}))
> 10
这里调用堆栈用于存储中间结果,这可以为您提供一个非常大的堆栈,具有深度递归或在返回中多次调用函数。
更好的方法是tail-recursion:
function sum_list(l, a)
if #l == 0 then
return a
else
local e = table.remove(l)
return sum_list(l, a + e)
end
end
print(sum_list({1,2,3,4}), 0)
> 10
在此示例中,在调用中传递累加器,因此调用堆栈不再用于存储,如果实现支持它,则可以将其转换为迭代。遗憾的是,并非所有递归函数都是尾递归的。在这种情况下累加器的问题是人们必须将它实例化为零,否则它会给出错误的结果。
解决方案就是你所做的:
function sum_list(l)
local function sum_list_helper(l, a)
if #l == 0 then
return a
else
local e = table.remove(l)
return sum_list_helper(l, a + e)
end
end
return sum_list_helper(l, 0)
end
创建本地函数,然后使用正确的实例化值调用该函数。
答案 1 :(得分:4)
如果你的意思是你不想使用包装函数,那么我认为你非常接近。这是你想要的那种东西吗?
function findall(xmltable, tag, results)
local results = results or {}
if xmltable[xml.TAG] == tag then table.insert(results, xmltable) end
for k, v in pairs(xmltable) do
if type(v) == "table" then findall(v, tag, results) end
end
return results
end