gpt4 book ai didi

ruby - 如何在 Enumerator::Lazy 方法中停止迭代?

转载 作者:数据小太阳 更新时间:2023-10-29 08:04:27 26 4
gpt4 key购买 nike

我正在尝试为 Ruby 2 的 Enumerator::Lazy 类实现一个 take_until 方法。它的工作方式应该与 take_while 类似,但在 yielded block 返回 true 时停止迭代。结果应包括生成的 block 匹配的项。

我的问题是如何发出迭代结束的信号?使用常规枚举器时,您可以在 each 方法中引发 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

要从该枚举器接收前五个项目,您需要评估第六个结果。这并不像它可能的那样懒惰。在我的用例中,这是不可取的,因为进程会阻塞。

为 Enumerator::Lazy 提供 take 的纯 Ruby 实现

标准库包含一个take 方法,它做的事情与我想要的类似。它不使用 block 作为条件,而是使用数字,但一旦达到该数字,它就会跳出迭代,而不是再评估一个项目。继续上面的例子:

enum.lazy.take(5).force

这不会到达第 6 个项目,因此不会阻塞。问题是标准库中的版本是用 C 实现的,我似乎无法弄清楚如何在纯 Ruby 中实现它。该方法的 ruby 实现将是一个可接受的答案。

提前致谢!

最佳答案

这是一个老问题,但无论如何:正如你所说,你真正需要的是一个Lazy#take_until,当然Lazy#take_while将需要获取下一个项目来决定是否打破或不。我一直无法使用 Lazy#new { ... } 实现 Lazy#take_until,显然没有中断机制。这是一个可能的解决方法:

class Enumerator::Lazy  
def take_until
Enumerator.new do |yielder|
each do |value|
yielder << value
break if yield(value)
end
end.lazy
end
end

关于ruby - 如何在 Enumerator::Lazy 方法中停止迭代?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20751856/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com