CSC/ECE 517 Spring 2015/ch1a 9 RA
Lazy Enumerators
Introduction
In Ruby 1.8 and Ruby 1.9 the problem with enumeration that generate infinite sequences is that we have to write special, non-greedy, versions of methods. But, if you’re using Ruby 2.0 or later, you have this support built in. If you call Enumerator#lazy on any Ruby enumerator, you get back an instance of class Enumerator::Lazy. Many basic class like Array and Hash has lazy method through Enumerator class.
The lazy methods returns a lazy enumerator whose methods Map/collect, flat_map/ collect_caoncat, select/ find_all, reject, grep, zip, take, #take_while, drop, #drop_while, and cycle enumerate values only on as-needed basis.
Differences
If you try to iterate over an infinite range in Enumerator then it will run into an endless loop while with Enumerator::Lazy you can avoid endless loop and get just the value you need.
> range = 1..Float::INFINITY > range.collect { |n| n**2}.first(10) #endless loop
but with lazy,
> range = 1..Float::INFINITY > range.lazy.collect { |n| n**2}.first(10) => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Enumerator::Lazy acts just like the original, but it re-implements methods such as select and map so that they can work with infinite sequences. The lazy versions of the various methods do not return arrays of data. Instead, it returns a new enumerator that includes its own special processing—below example of map method returns an enumerator.
> range = 1..100 > range.map{|n| n**2}.take(10) #returns array => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
but with lazy,
> range.lazy.map{|n| n**2}.take(10) #returns enumerator =>#<Enumerator::Lazy:#<Enumerator::Lazy:#<Enumerator::Lazy:1..100>:map>:take(10)>
Examples
require 'date' require ‘benchmark’ Benchmark.bm(8) do |x| x.report("Non Lazy :") do puts (Date.new(2015)..Date.new(9999)).select{|d| d.day == 13 and d.friday?}.first(10) end x.report("Lazy :") do puts (Date.new(2015)..Date.new(9999)).lazy.select{|d| d.day == 13 and d.friday?}.first(10) end end