Taking It One Element at a Time

Posted by 'Tine Zekis on May 03, 2015 · 4 mins read

Assignment: Technical Blog | Enumerable Methods

In Ruby, Enumerable is a module that allows us to access each element out of a collection, one at a time. It is used as a mix-in for various classes that contain multiple elements, such as Arrays, Hashes, and Ranges. If we think of enumerable as an adjective, then Enumerator is the noun form. It is a method object (a noun that performs a verb), a tool we can use to enumerate an action, one at a time, on every element of another object. For now, we will focus on one such enumerator: the map method.

Enumerable#map is an enumerator that returns a new array in which each index is the result of performing the block one time on each element in a collection. For example:

(1..5).map { |i| i * i }
=> [1, 4, 9, 16, 25]
The block (in curly brackets) directed this map method to take each element of the range 1 - 5 (inclusive) and multiply the element by itself. The result is an array containing a list of the first five perfect squares. It is important to note, however, that if the action in the block does not have a return value, the array created will have a nil value in each index. For example, the print method will print a string to the console, but does not return any value. So, if we wanted to print each element in our range with a space in between, we might do so thusly:
(1..5).map { |i| print i.to_s + ' ' }
=> 1 2 3 4 5 => [nil, nil, nil, nil, nil]
Let's talk a little bit about what went on here. The block instructs our map method to take each element in the range and print that element (converted to a string) and add a space afterward. The print method does not create a line break, so each of our elements (as well as the next line in the terminal) all get printed to one line. The next piece is the array that got returned. Each time we printed an element, the nil value was returned in our array. This is why we see nil five times, one for each element of the range.

It is also important to note that if no block is given, the return is an enumerator object. For example:

=> <Enumerator: 1..5:map>
Thus, we can later determine what this enumerator will do. For example, we will create an enumerator called enum:
enum = (1..5).map
=> <Enumerator: 1..5:map>
example.map { |i| i + 1 }
=> [2, 3, 4, 5, 6]
After the enumerator was created, we are able to apply the map block with new content. In this case, we added 1 to each element.

Well, this has been just a small look into one thing that enumerators can do. I hope it has piqued your interest and that you will investigate enumerator methods further, as I will. Please check in again as I continue my journey into web development. I will continue to post about my learnings along the way. And, for your sake and mine, I'm going to resist the map pun here. Until next time, happy coding!