如何在Ruby中获取一个惰性数组?

car*_*ips 30 ruby lazy-evaluation

如何在Ruby中获取一个惰性数组?

在Haskell中,我可以谈论[1..],这是一个无限的列表,根据需要懒洋洋地生成.我也可以做类似的事情iterate (+2) 0,它应用我给它的任何函数来生成一个惰性列表.在这种情况下,它会给我所有偶数.

我确信我可以在Ruby中做这些事情,但似乎无法弄清楚如何.

car*_*ips 41

使用Ruby 1.9,您可以使用Enumerator类.这是文档中的一个示例:

  fib = Enumerator.new { |y|
    a = b = 1
    loop {
      y << a
      a, b = b, a + b
    }
  }

  p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Run Code Online (Sandbox Code Playgroud)

此外,这是一个很好的技巧:

  Infinity = 1.0/0

  range = 5..Infinity
  p range.take(10) #=> [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Run Code Online (Sandbox Code Playgroud)

这个只适用于连续值.

  • 他们不必连续:(10..100).step(20).take(5)#=> [10,20,30,40,50] (5认同)
  • 在Ruby 1.8中,你可以'require'backports'`来获得这个功能:-) (2认同)
  • 注意做`fib.map {| x | x + 1} .take(10)`不起作用,因为map会尝试创建一个数组.另请注意,如果你执行两次`fib.take(10)`,元素将被计算两次(与惰性列表不同,其中元素在计算后保存在内存中).所以这并不完全等同于懒惰列表. (2认同)
  • 为了使枚举器等效于`fib.map`,你需要做`fib.enum_for(:map)`. (2认同)

gre*_*sen 21

最近Enumerable :: Lazy已添加到ruby trunk.我们将在ruby 2.0中看到它.特别是:

a = data.lazy.map(&:split).map(&:reverse)
Run Code Online (Sandbox Code Playgroud)

不会立即评估.
结果是Enumerable :: Lazy的实例,可以进一步延迟链接.如果你想得到一个实际的结果 - 使用#to_a,#take(n)(#take现在也很懒,使用#to_a或者#force等)等等.
如果你想要更多关于这个主题和我的C补丁 - 请参阅我的博客文章Ruby 2.0 Enumerable :: Lazy


hor*_*guy 6

懒惰范围(自然数):

Inf = 1.0/0.0
(1..Inf).take(3) #=> [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

懒惰范围(偶数):

(0..Inf).step(2).take(5) #=> [0, 2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)

注意,您还可以Enumerable使用某些方法进行扩展,以便更方便地使用惰性范围(等等):

module Enumerable
  def lazy_select
    Enumerator.new do |yielder|
      each do |obj|
        yielder.yield(obj) if yield(obj)
      end
    end
  end
end

# first 4 even numbers
(1..Inf).lazy_select { |v| v.even? }.take(4)

output:
[2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)

更多信息:http: //banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/

还有lazy_map和lazy_select的实现Enumerator,可以在这里找到类:http: //www.michaelharrison.ws/weblog/? p = 163