From: Andrew Wagner on
[Note: parts of this message were removed to make it a legal post.]

How can I get a lazy array in Ruby? E.g., 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.
Anyway, I'm sure I can do such things in Ruby, but can't seem to work out
how.

From: skim on
[Note: parts of this message were removed to make it a legal post.]

Ruby Arrays dynamically expand as needed. You can apply blocks to them to
return things like even numbers.

array = []
array.size # => 0
array[0] # => nil
array[9999] # => nil
array << 1
array.size # => 1
array << 2 << 3 << 4
array.size # => 4

array = (0..9).to_a
array.select do |e|
e % 2 == 0
end

# => [0,2,4,6,8]

Does this help?

On Sun, Aug 1, 2010 at 17:45, Andrew Wagner <wagner.andrew(a)gmail.com> wrote:

> How can I get a lazy array in Ruby? E.g., 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.
> Anyway, I'm sure I can do such things in Ruby, but can't seem to work out
> how.
>

From: jeremy Ruten on
Ruby 1.9 has the Enumerator class, which can act like a lazy list I
think. A good example is given in the documentation:

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.

jeremy

On Sun, Aug 1, 2010 at 8:56 PM, skim <skim.la(a)gmail.com> wrote:
> Ruby Arrays dynamically expand as needed.  You can apply blocks to them to
> return things like even numbers.
>
> array = []
> array.size # => 0
> array[0] # => nil
> array[9999] # => nil
> array << 1
> array.size # => 1
> array << 2 << 3 << 4
> array.size # => 4
>
> array = (0..9).to_a
> array.select do |e|
>  e % 2 == 0
> end
>
> # => [0,2,4,6,8]
>
> Does this help?
>
> On Sun, Aug 1, 2010 at 17:45, Andrew Wagner <wagner.andrew(a)gmail.com> wrote:
>
>> How can I get a lazy array in Ruby? E.g., 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.
>> Anyway, I'm sure I can do such things in Ruby, but can't seem to work out
>> how.
>>
>

From: Benoit Daloze on
On 2 August 2010 05:22, jeremy Ruten <jeremy.ruten(a)gmail.com> wrote:
> Ruby 1.9 has the Enumerator class, which can act like a lazy list I
> think. A good example is given in the documentation:
>
>  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.
>
> jeremy
>
> On Sun, Aug 1, 2010 at 8:56 PM, skim <skim.la(a)gmail.com> wrote:
>> Ruby Arrays dynamically expand as needed.  You can apply blocks to them to
>> return things like even numbers.
>>
>> array = []
>> array.size # => 0
>> array[0] # => nil
>> array[9999] # => nil
>> array << 1
>> array.size # => 1
>> array << 2 << 3 << 4
>> array.size # => 4
>>
>> array = (0..9).to_a
>> array.select do |e|
>>  e % 2 == 0
>> end
>>
>> # => [0,2,4,6,8]
>>
>> Does this help?
>>
>> On Sun, Aug 1, 2010 at 17:45, Andrew Wagner <wagner.andrew(a)gmail.com> wrote:
>>
>>> How can I get a lazy array in Ruby? E.g., 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.
>>> Anyway, I'm sure I can do such things in Ruby, but can't seem to work out
>>> how.
>>>
>>
>

So, with Enumerator it should be:

even = Enumerator.new { |y|
i = 0
loop {
y << i
i += 2
}
}

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

But that is not really common practice in Ruby (Enumerator for so
simple things).

You would probably need something like (0..max).step(2) { |even_n| p even_n }

B.D.

From: Brian Candler on
Benoit Daloze wrote:
> So, with Enumerator it should be:
>
> even = Enumerator.new { |y|
> i = 0
> loop {
> y << i
> i += 2
> }
> }
>
> p even.take(5) # => [0, 2, 4, 6, 8]
>
> But that is not really common practice in Ruby (Enumerator for so
> simple things).

In any case, that Enumerator block form is only syntactic sugar. You can
do the same without using the Enumerator class:

even = Object.new
def even.each(&blk)
(2..1.0/0).step(2,&blk)
end
even.extend Enumerable
p even.take(5)

In both cases, all you're doing is having 'each' generate an infinite
series, and then truncating it with 'take'.

This is not useful normally, because you can't chain it - most of the
Enumerable functions like 'map', 'select' etc collect the full results
into an Array before continuing.

However, it's quite possible to have these functions process one element
at a time without generating the intermediate arrays, and there is an
implementation of this in the 'facets' library:


>> RUBY_VERSION
=> "1.8.6"
>> require 'rubygems'
=> true
>> require 'facets/enumerator'
=> true
>> require 'facets/enumerable/defer'
=> true
>> (1..1_000_000_000).defer.select { |i| i % 2 == 0 }.map { |i| i+100 }.take(10).to_a
=> [102, 104, 106, 108, 110, 112, 114, 116, 118, 120]


Infinite lists are no problem here - each element propagates through the
whole chain before the next. You're processing 'horizontally' rather
than 'vertically'.

Note that this doesn't use Threads or Fibers, it's efficient, and it
works in ruby 1.8. For the implementation details, see the Denumerator
class.
--
Posted via http://www.ruby-forum.com/.