我想为Ruby 2的Enumerator :: Lazy类实现一个take_until
方法。它的工作原理与take_while
类似,但当代码块返回true时停止迭代。结果应该包括产生的块匹配的项目。如何在Enumerator :: Lazy方法中停止迭代?
我的问题是我如何表示迭代的结束已达到?使用常规枚举器时,可以在每个方法中引发StopIteration错误,以表示迭代器的结束。但是,这似乎并不适用于懒惰的枚举:
class Enumerator::Lazy
def take_until
Lazy.new(self) do |yielder, *values|
yielder << values
raise StopIteration if yield *values
end
end
end
(1..Float::INFINITY).lazy.take_until{ |i| i == 5 }.force
我也试图突破块无效。 The documentation for Enumerator::Lazy似乎也没有帮助。
为什么使用take_while
不是一个有效的选项。
take_while的主要问题是,从本质上讲,它会尝试评估比您需要的更多的物品。在我的应用程序中,枚举器不会产生数字,而是通过网络获取消息。试图评估一个不存在的信息(但是?)是一种非常不受欢迎的阻止行为。这通过以下人为示例来说明:
enum = Enumerator.new do |y|
5.times do |i|
y << i
end
sleep
end
enum.lazy.take_while{ |i| i < 5 }.force
要从此枚举器接收前五项,您将需要评估第六个结果。这并不像它那样懒惰。在我的使用情况下,这是不可取的,因为这个过程会被阻止。
提供枚举::懒惰
标准库包括take
方法,做类似于我想要的东西纯Ruby实现的take
。它不会使用块作为条件,而是使用数字,但是一旦达到该数字,它就会跳出迭代,而不是评估另外一个项目。继上面的例子:
enum.lazy.take(5).force
这没有得到第6项,所以不阻止。问题是标准库中的版本是用C语言实现的,我似乎无法弄清楚这是如何在纯Ruby中实现的。该方法的红宝石实现将是一个可以接受的答案。
提前致谢!
我讨厌问,但不是你只是使用take_while并根据需要修改条件? –
这是一个有效的问题,但我认为答案是:不,我不能。我的使用案例涉及到一系列的响应,我特别想要在遇到某些情况时对序列进行分隔。 Take_while不会包含匹配的项目本身,而是将顺序返回到第一个“未命中”。希望这是有道理的。 –
所以'take_until'会否定一个'take_while',它会做一个额外的'yield next'? – steenslag