How to use an enumerator

enumeration, enumerator, ruby

Solution

The main distinction between an `Enumerator` and most† other data structures in the Ruby core library (`Array`, `Hash`) and standard library (`Set`, `SortedSet`) is that an `Enumerator` can be infinite. You cannot have an `Array` of all even numbers or a stream of zeroes or all prime numbers, but you can definitely have such an `Enumerator`:

evens = Enumerator.new do |y|
  i = -2
  y << i += 2 while true
end

evens.take(10)
# => [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

zeroes = [0].cycle

zeroes.take(10)
# => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

So, what can you do with such an `Enumerator`? Well, three things, basically.

`Enumerator` mixes in `Enumerable`. Therefore, you can use all `Enumerable` methods such as `map`, `inject`, `all?`, `any?`, `none?`, `select`, `reject` and so forth. Just be aware that an `Enumerator` may be infinite whereas `map` returns an `Array`, so trying to `map` an infinite `Enumerator` may create an infinitely large `Array` and take an infinite amount of time.

There are wrapping methods which somehow "enrich" an `Enumerator` and return a new `Enumerator`. For example, `Enumerator#with_index` adds a "loop counter" to the block and `Enumerator#with_object` adds a memo object.

You can use an `Enumerator` just like you would use it in other languages for external iteration by using the `Enumerator#next` method which will give you either the next value (and move the `Enumerator` forward) or `raise` a `StopIteration` exception if the `Enumerator` is finite and you have reached the end.

† Eg., an infinite range: `(1..1.0/0)`

Problem

In the Ruby Array Class documentation, I often find: If no block is given, an enumerator is returned instead. Why would I not pass a block to `#map`? What would be the use of my doing just: ``` [1,2,3,4].map ``` instead of doing: ``` [1,2,3,4].map{ |e| e * 10 } # => [10, 20, 30, 40] ``` Can someone show me a very practical example of using this enumerator?

Original source