Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Loops 如何在Lua中对二维表生成迭代器?_Loops_Multidimensional Array_Lua_Iterator - Fatal编程技术网

Loops 如何在Lua中对二维表生成迭代器?

Loops 如何在Lua中对二维表生成迭代器?,loops,multidimensional-array,lua,iterator,Loops,Multidimensional Array,Lua,Iterator,我有一个由表组成的lua表,所以它是二维的:根->子->孙 此层次结构的任何级别都不能保证“类似于数组”。第一个级别有带“零间隙”的整数,第二个级别甚至没有整数索引(而是表索引) 所讨论的表是lib中的私有结构。我想为库用户提供一种解析其孙子的方法。我不太关心它们被解析的顺序,只要它们都是 我想到的第一件事是使用接受回调的函数: -- this scope has access to root function eachGrandChild(callback) for _,child in

我有一个由表组成的lua表,所以它是二维的:根->子->孙

此层次结构的任何级别都不能保证“类似于数组”。第一个级别有带“零间隙”的整数,第二个级别甚至没有整数索引(而是表索引)

所讨论的表是lib中的私有结构。我想为库用户提供一种解析其孙子的方法。我不太关心它们被解析的顺序,只要它们都是

我想到的第一件事是使用接受回调的函数:

-- this scope has access to root 
function eachGrandChild(callback)
  for _,child in pairs(root) do
    for index,grandChild in pairs(child)
      callback(index, grandChild)
    end
  end
end
用法:

-- no access to root, only to eachGrandChild
eachGrandChild(function(index, grandChild) print(index, grandChild) end)
这一点是可以理解的

我的问题是:我可以用一个类似的功能来代替吗?

我说的是一些可以让我做到这一点的事情:

for index,grandChild in iterator() do
  print(index, grandChild)
end
我已经想了一段时间了,但是我没办法解决它。我看到的所有示例都使用数字来轻松地在每次迭代中“管理迭代器的状态”。因为我没有数字,所以有点卡住了。

使编写这种迭代器变得容易。协同程序是一个函数,其执行可以暂停和恢复,概念上类似于线程。一个协同程序可以包含深度嵌套的循环,从最内部的循环中产生一个值,然后在恢复时从停止的地方继续。当它产生时,恢复它的调用方可以接收产生的值

在您的例子中,将
eachGrandChild
转换为生成孙子的生成器函数

function eachGrandChild(root)
  for _,child in pairs(root) do
    for index,grandChild in pairs(child) do
      coroutine.yield(index, grandChild)
    end
  end
end
然后使用
coroutine.wrap
创建一个函数,该函数将为生成器创建一个coroutine,并在每次调用该函数时恢复该函数

function grandChildren(t)
    return coroutine.wrap(function() eachGrandChild(t) end)
end
现在您有了迭代器:

for key, val in grandChildren(root) do
    print(key, val)
end

我同意Mud的观点,即协同程序是解决问题的最佳方法

为了便于比较,我编写了一个没有协同例程的迭代器

为每个元素调用第一个函数
eachGrandChild
。它使用一个
state
变量,包含两个索引(顶层和二级)

迭代器由helper函数初始化:

function grandChildren(root)
  return eachGrandChild, {childIndex = next(root)}
end
现在迭代器可以正常使用了:

for key, val in grandChildren(root) do
    print(key, val)
end

与基于协同程序的版本相比,
eachGrandChild
有更多的代码行,更难阅读。

。我说的“管理函数状态”部分实际上是在对我喊“协同程序”,但我没有把这些点联系起来。我有点担心执行速度(每帧将执行多次解析循环,因此速度必须相当快),但我会做一些测试。@kikito:您的直接回调方法肯定会更有效,部分原因是减少了函数调用开销(恢复、产量)。但这并不像你想象的那么糟糕(Lua的合作项目是)。例如,如果您对协程实现与prapin的实现进行基准测试,我怀疑您会发现协程更快。您在所有方面都是正确的。即使每次创建新的匿名函数时,回调代码也是最快的。协同程序完成同样的工作需要大约200%的时间,而基于下一个的解决方案需要大约220%的时间。所以我想我会坚持回拨。尽管如此,这还是一次很好的学习经历!:)只要记住。是的,200%听起来很糟糕,但我们谈论的是几微秒之间的差异。你是说每帧有数千次这样称呼吗?“过早的邪恶是所有优化的根源”:我知道这句话。是的,每帧将调用数千次-它将位于冲突库的中心(
root
实际上是一个空间索引),谢谢您的回答。尽管如此,我还是会尝试这两种方法——你的方法可能更有效,如果稍微长一点的话。如果可能的话,我会声明这两个答案都是正确的。你肯定应该得到一个+1,我已经冒昧地对迭代器代码进行了一点重构——名称而不是幻数,一段时间而不是重复直到,以及一个简化的“孙辈用完”条件。我还从状态中删除了
root
,因为假定它在范围中可用。我希望你不介意我编辑你的答案。@kikito谢谢你编辑代码。这一点现在更具可读性。
for key, val in grandChildren(root) do
    print(key, val)
end