Ruby enumerators
A quick refresher about enumerable and enumerators in ruby.
Enumerable
The class must provide a method each, which yields successive members of the collection. If Enumerable#max, #min, or #sort is used, the objects in the collection must also implement a meaningful <=> operator.
The classical pattern is called iterator. The iterator can be external and internal: it’s external when the iteration is controlled by the client (basically a visible for loop over the collection), internal when it is controlled by the collection object itself (and the collection object has methods that iterate over the collection itself).
Enumerators
Enumerator is a class that wraps an Enumerable object and adds the external iteration, ie the next
method. You can create one with
You can make an Enumerator from an Enumerable with the to_enum
method.
If you next
after the last element a StopIteration
exception will be raised - note that the loop
method rescues it.
A less common way to create an Enumerator is with Object#enum_for(method = :each)
, which will create an Enumerator iterating by the method passed as parameter.
Many Enumerable methods, when called with no parameters, actually return an Enumerator, like
But also #times
, #upto
, String#each_char
and more.
You can build an Enumerator with this syntax too:
The y
block parameter is the yielder, that takes thr yield
parameter, aliased as <<
.
Something to double values:
Lazy enumerators
Some operations are impossible when an enumerator is infinite because they rely on having all the elements of the collection. Lazy enumerators enumerate the values only when they’re needed. They implement the various map
, select
, take
, etc in a lazy way, so that they do not perform the operation immediately but only when their output is called externally:
The methods that expand the enumerator to an array are to_a
and its alias force
.
Suppose you want the first 100 powers of 2 that end in 4: