![](/img/trans.png)
[英]Find previous element in Ruby array Enumerable Enumerator
[英]create a ruby enumerable from a first element, and a function to get the next element from the previous one
在 Scala 中,您可以从第一个元素定义 stream ,并从前一个元素中定义一个 function 以获得下一个;
Stream.iterate(1)(x => 2 * x + 1)
Ruby中是否存在这样的东西?
我们当然可以手卷它-
module Kernel
def stream
Enumerator.new do |y|
that = self
while true
y << that
that = yield that
end
end
end
end
但它是惯用的吗? 已经有这样的事情了吗?
您要问的问题称为展开 (在scala中称为Stream.iterate
),或更笼统地说是变形 。 它是折叠的精确的类别理论对偶(在红宝石中称为Enumerable#inject
),也称为同形同构 。
已经有这样的东西了吗?
不幸的是,核心或标准库中没有执行此功能的方法。
但这是惯用的吗?
我可能会使其成为Enumerator
的单例方法,并使用Kernel#loop
代替while true
,但这就是它。 否则,是的,您的代码很惯用。
当我们使用它时,我们称之为unfold
:
def Enumerator.unfold(start)
new do |y|
loop do
y << start
start = yield start
end
end
end
我不会知道达成共识的惯用方式。 由于您的代码似乎无法产生所需的效果,因此,我将向您提供一些示例,说明如何实现它。
您可以使用Fiber
创建外部迭代的展开,如下所示:
def stream(init, &block)
Fiber.new do
memo = init
loop do
Fiber.yield memo
memo = block.call memo
end
end
end
a = stream(1){ |x| 2 * x + 1 }
a.resume # => 1
a.resume # => 3
a.resume # => 7
a.resume # => 15
如果您更喜欢Enumerator::Lazy
及其所有超能力,请考虑以下事项:
def stream2(init, &block)
Enumerator.new do |yielder|
memo = init
loop do
yielder << memo
memo = block.call memo
end
end.lazy
end
a2 = stream2(1){ |x| 2 * x + 1 }
a2.next # => 1
a2.next # => 3
a2.next # => 7
a2.take(10).force # => [1, 3, 7, 15, 31, 63, 127, 255, 511, 1023]
行为将与此相同:
def stream3(init, &block)
memo = init
(1..Float::INFINITY).lazy.map{ |_| memo = block.call(memo) }
end
最后一个可能是最惯用的,并且最好地隐藏了枚举的内部。 但是,我个人不喜欢stream3
因为它产生数字只是为了丢弃它们。
高温超导
Ruby 2.7 引入了Enumerator#produce
,它执行George Simms最初询问的 AFAICT。
所以 Ruby 相当于原始 Scala 片段:
Stream.iterate(1)(x => 2 * x + 1)
将会:
Enumerator.produce(1) { |x| 2 * x + 1 }
并导致:
irb> Enumerator.produce(1) { |x| 2 * x + 1 }.first(5)
=> [1, 3, 7, 15, 31]
irb> _
其中 - 如果您喜欢编号块参数(另一个 Ruby 2.7 功能) - 也可以写成:
irb> Enumerator.produce(1) { 2 * _1 + 1 }.first(5)
=> [1, 3, 7, 15, 31]
irb> _
在Ruby中,您可以使用Enumerable#inject
:
[7, 8, 9].inject(1){ |carry, item| 2 * carry + item }
该块的返回值将用作进位变量的下一个值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.