How can I get a lazy array in Ruby?

Lazy range (natural numbers):

Inf = 1.0/0.0
(1..Inf).take(3) #=> [1, 2, 3]

Lazy range (even numbers):

(0..Inf).step(2).take(5) #=> [0, 2, 4, 6, 8]

Note, you can also extend Enumerable with some methods to make working with lazy ranges (and so on) more convenient:

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]

More info here: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/

There are also implementations of lazy_map, and lazy_select for the Enumeratorclass that can be found here: http://www.michaelharrison.ws/weblog/?p=163


Recently Enumerable::Lazy has been added to ruby trunk. We'll see it in ruby 2.0. In particular:

a = data.lazy.map(&:split).map(&:reverse)

will not be evaluated immediately.
The result is instance of Enumerable::Lazy, that can be lazy chained any further. If you want to get an actual result - use #to_a, #take(n) (#take is now lazy too, use #to_a or #force), etc.
If you want more on this topic and my C patch - see my blog post Ruby 2.0 Enumerable::Lazy


With Ruby 1.9 you can use the Enumerator class. This is an example from the docs:

  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]

Also, this is a nice trick:

  Infinity = 1.0/0

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

This one only works for consecutive values though.