Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get a lazy array in Ruby?

How can I get a lazy array in Ruby?

In Haskell, I can talk about [1..], which is an infinite list, lazily generated as needed. I can also do things like iterate (+2) 0, which applies whatever function I give it to generate a lazy list. In this case, it would give me all even numbers.

I'm sure I can do such things in Ruby, but can't seem to work out how.

like image 622
carlfilips Avatar asked Aug 03 '10 00:08

carlfilips


People also ask

What does lazy do in Ruby?

Enumerator::Lazy is a special type of Enumerator , that allows constructing chains of operations without evaluating them immediately, and evaluating values on as-needed basis. In order to do so it redefines most of Enumerable methods so that they just construct another lazy enumerator.

What is lazy evaluation in Ruby?

Lazy enumeration means that an expression is only processed when we are working with the result. There are languages that are lazy by default, like Haskell, and many others are implementing a way to lazily evaluate expressions.

Can you add arrays in Ruby?

This can be done in a few ways in Ruby. The first is the plus operator. This will append one array to the end of another, creating a third array with the elements of both. Alternatively, use the concat method (the + operator and concat method are functionally equivalent).

What does .first mean in Ruby?

The first() is an inbuilt method in Ruby returns an array of first X elements. If X is not mentioned, it returns the first element only. Syntax: range1.first(X) Parameters: The function accepts X which is the number of elements from the beginning. Return Value: It returns an array of first X elements.


2 Answers

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.

like image 126
carlfilips Avatar answered Oct 02 '22 12:10

carlfilips


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

like image 30
gregolsen Avatar answered Oct 02 '22 12:10

gregolsen