Enumerator is used for iterating over a collection of items. It allows both internal and external iteration.
So how do we Create an Enumerator?
There are 3 different ways to create it. They are from,- A Block,
- An Enumerable,
- A Blockless Enumerable Method Call.
From a Block
We can create an enum by passing a block to its constructor. A yielder object will be passed to this block. The yielder’s#<<
method can be used to define the elements. Enumerator#next
can then be used to provide iteration.
Eg:
enum = Enumerator.new do |yielder| yielder << "Red" yielder << "Panthers" end enum.next # "Red" # StopIteration: when it reached an end
From an Enumerable
The most common way to create anEnumerator
is from an Enumerable
object, specifically, an object that defines a #each
method. Object#to_enum
is implemented to return a new Enumerator which
will enumerate by sending #each
to its receiver.
Eg:
array = [1, 2, 3] enum = array.to_enum enum.each {|n| n * 2} # 2 4 6
From a Blockless Enumerable Method Call
There are severalEnumerable
methods that take a block and returns an Enumerator
when called without a block. For instance, calling Array#select
without a block will return an Enumerator
with an #each
method that will filter like #select.
These blockless calls offer a concise alternative to Object#to_enum
.
Eg:
array = [1, 2, 3, 4] enum = array.select enum.each {|n| n % 2 == 0} # [2, 4]
When do we use an Enumerator?
We can use this type instead of defining many constants for fields (such as astatus).
For example, status can have values active and inactive in different condition. So that, we can use this type as below:
Eg:
status =%w(active inactive).each puts status.class # => Enumerator puts status.next # => active puts status.next # => inactive puts status.next # raises StopIterationSo by using it, we can simplify our code as above.
Why are they so special?
Well,
- It provides enumeration functionality to objects without it.
- You can control the iteration process in an efficient way using different methods like .each, .select, .next, .peek etc.
- There is a feature called Lazy enumerator, which will prevent iterate over an infinite collection.
- It saves a lot of typing(see above example), which makes the programmer more efficient.