Project

General

Profile

Feature #708 ยป lazy_enum.rb

candlerb (Brian Candler), 11/03/2008 06:54 PM

 
# Inside Enumerator, redefine those Enumerable methods which return an Array
# so that they return another Enumerator instead. This allows Enumerator
# chaining, where the calls go 'horizontally' without creating any
# intermediate arrays, including processing of infinite enumerations. e.g.
#
# class Fib
# def initialize(a=1,b=1)
# @a, @b = a, b
# end
# def each
# a, b = @a, @b
# yield a
# while true
# yield b
# a, b = b, a+b
# end
# end
# end
#
# Fib.new.to_enum.select { |i| i % 2 == 0 }.map { |i| "<#{i}>" }.
# each_with_index { |i,cnt| puts i; break if cnt >= 20 }
#
# Note: not all methods have been implemented here, just some sample ones.

class Enumerator
def map(&blk)
self.class.new do |y|
each do |e|
y << blk[e]
end
end
end

def select(&blk)
self.class.new do |y|
each do |e|
y << e if blk[e]
end
end
end

def take(n)
self.class.new do |y|
count = 0
each do |e|
break if n <= count
y << e
count += 1
end
end
end
def skip(n)
self.class.new do |y|
count = 0
each do |e|
y << e unless count <= n
count += 1
end
end
end
end

# This reported separately as Feature #666.
# This could go in Enumerator, but it makes sense in Enumerable too IMO.
module Enumerable
def to_hash
each_with_object({}) { |(k,v),o| o[k] = v }
end
end

if __FILE__ == $0
big = (1..1_000_000_000_000).to_enum
big.select { |i| i % 2 == 1 }.map { |i| i + 100 }.skip(5).take(10).
each { |i| puts i }

# Normal version:
h = {1=>2, 3=>4}
p h.select { true }
# This is the chainable Enumerator version:
p h.to_enum.select { true }.to_hash
end
    (1-1/1)