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?
Enumerations make for clearer and more readable code, particularly when meaningful names are used. The benefits of using enumerations include: Reduces errors caused by transposing or mistyping numbers. Makes it easy to change values in the future.
An enumerated type is a type whose legal values consist of a fixed set of constants. Common examples include compass directions, which take the values North, South, East and West and days of the week, which take the values Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, and Saturday.
In C++ programming, enum or enumeration is a data type consisting of named values like elements, members, etc., that represent integral constants. It provides a way to define and group integral constants. It also makes the code easy to maintain and less complex.
An enum class can include methods and fields just like regular classes. When we create an enum class, the compiler will create instances (objects) of each enum constants. Also, all enum constant is always public static final by default.
Good question.
What if we want to do multiple things with the enumerator that is created? We don't want to process it now, because it means we may need to create another later?
my_enum = %w[now is the time for all good elves to get to work].map # => #<Enumerator: ["now", "is", "the", "time", "for", "all", "good", "elves", "to", "get", "to", "work"]:map>
my_enum.each(&:upcase) # => ["NOW", "IS", "THE", "TIME", "FOR", "ALL", "GOOD", "ELVES", "TO", "GET", "TO", "WORK"]
my_enum.each(&:capitalize) # => ["Now", "Is", "The", "Time", "For", "All", "Good", "Elves", "To", "Get", "To", "Work"]
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With