包装迭代器以仅遍历某些值

我有一个 Lua 迭代器函数,但我无法控制它:

for x, y, z in otherfunc(stuff) do
   ...
end

我想编写一个通用的 Lua 包装器函数来跳过它返回的某些值,从我的用户隐藏这个实现细节:

for x, y, z in myfunc(stuff) do
   -- 这里不会出现每个 x/y/z 三元组
end

虽然我这里恰好有三个返回值,但我应如何以通用的方式处理任意数量的返回值?

点赞
用户405017
用户405017

针对一种已知的具有特定返回值的迭代器函数和硬编码的选择标准,我使用了以下代码:

function myfunc(...)
   local generator, constant, x,y,z in otherfunc(...)
   return function()
      repeat x,y,z = generator(constant,x,y,z)
      until (not x) or x+y+z > 7
      if x then return x,y,z end
   end
end

以上代码将重复调用otherfunc()迭代器函数,但仅在其返回值的总和大于7时yield x/y/z值。

更一般地,下面是一个函数,它接受一个选择函数和一个迭代器,并处理从迭代器返回的任意数量的返回值,并仅在选择器函数返回一个truthy值时返回它们:

function subiterate(selector, generator, constant, ...)
   local values = {...}
   return function()
      repeat values = table.pack(generator(constant, table.unpack(values)))
      until not values[1] or selector(table.unpack(values))
      return table.unpack(values)
   end
end

local function everythird(i,_)
   return (i-1)%3==2
end

for i, n in subiterate(everythird, ipairs{'a','b','c','d','e','f'}) do
   print(i, n)
end
--> 3   c
--> 6   f

我不保证通用函数的速度,因为有很多pack()unpack()在进行。但是它确实有效。我欢迎任何更有效的处理迭代器任意数量返回值的方法。

2019-08-19 15:46:04
用户6834680
用户6834680
local function check_and_return(my_state, x, ...)
   if x == nil or my_state[1](x, ...) then
      return x, ...
   else
      return check_and_return(my_state, my_state[2](my_state[3], x))
   end
end

local function my_generator(my_state, prev_x)
   return check_and_return(my_state, my_state[2](my_state[3], prev_x))
end

function subiterate(selector, generator, state, init_x)
   -- 迭代器是无状态的
   -- 循环初始化时不创建闭包
   -- 循环初始化时创建一个表
   -- 每一步都不创建表
   return my_generator, {selector, generator, state}, init_x
end

使用示例:

local function everythird(i,_)
   return (i-1)%3==2
end

for i, n in subiterate(everythird, ipairs{'a','b','c','d','e','f'}) do
   print(i, n)
end
--> 3   c
--> 6   f
2019-08-19 18:53:26