Lesson Wednesday

Now that we've had some practice with looping in Ruby, let's look at other methods that can be used to iterate over a collection. In a previous lesson, we discussed using modules for mixins, including a Ruby module called Enumerable. This module provides an extremely powerful set of methods for iterating over collections such as arrays, ranges and hashes.

Enumerable#map()


We'll start by taking a look at one of Enumerable’s most powerful methods: map(). You’ve already learned about JavaScript’s map() function; Ruby’s version of the method works in a similar manner.

Here's an example. In a previous lesson, we created an array_doubler method. In order to return an array with each element doubled, we had to create a new array and then push each doubled value into it. Here’s the code:

def array_doubler(array)
  new_array = []
  array.each do |array_element|
    new_array.push(array_element * 2)
  end
  new_array
end

Unlike each(), map() actually transforms the elements as it iterates over them, which means we don't need to push the values into a new array. With map(), we can rewrite the above method like this:

def array_doubler(array)
  array.map { |a| a * 2 }
end

That’s a lot less code!

You’ll notice that we’re using curly braces with map(). In Ruby, {} is shorthand for a do...end block. This means we could just as easily write array.map { |a| a * 2 } like this instead:

array.map do |a|
  a * 2
end

Generally {} is used when a block is only one line. When a block is more than one line, we should use do...end instead. Since map() makes our code so much more efficient, it’s usually used with {}.

Note that map() will transform each element into the return value of the statement inside the block, so we do need to be somewhat careful. For instance, this wouldn't work as intended:

def array_doubler(array)
  array.map { |a| puts a * 2 }
end

array_doubler([1,2,3])
2
4
6
=> [nil, nil, nil]

While puts prints the correct value in the terminal, the actual return value of puts is nil. In other words, we've just created a method that returns an array full of nil values.

Enumerable#select() and Enumerable#reject()


Let’s take a look at a few other Enumerable methods.

select() allows you to grab all elements from a collection that match a given condition. Here are a few examples:

> range = 1..10
> range.select { |r| r > 5 }
=> [6, 7, 8, 9, 10]
> range.select { |r| r.even? }
=> [2, 4, 6, 8, 10]

In the first statement, we select all elements in the range that are greater than 5. In the second, we select all elements that are even. There’s also a reject() method which does the exact opposite of select. For instance:

> range.reject { |r| r > 5 }
=> [1, 2, 3, 4, 5]

Here all elements that are greater than 5 are removed from the range.

Enumerable#reduce()


Let’s look at a method called reduce(), which we can use to take a collection and reduce it to a single value. For instance, we can use it to perform a mathematical operation on a collection. Here's an example where we use reduce() to sum or multiply all of an array’s elements:

> [1,2,3].reduce(:+)
=> 6

This adds all the elements in the array together. reduce can take two arguments: an initial value and a symbol that represents the mathematical operation you want to call. If you don’t pass in an initial value, reduce will begin with the first value in the collection.

Here are a few more examples of reduce() in action:

> [1,2,3].reduce(2, :*)
=> 12
> (1..3).reduce(:-)
=> -4

Think of reduce() as literally reducing a collection down to a single element. This method can also be used in other interesting ways. For instance, if we had an array of words and we wanted to find out which one was the longest or shortest, we could use the reduce() method to reduce the array to that word.

Check out the Enumerable documentation to find out more. While you’re at it, take a look at Enumerable’s other methods as well. See if you can incorporate a few into your projects this section. To become a good Ruby developer, it's absolutely essential to have a strong understanding of Enumerable and its methods.

Terminology


map(): An extremely powerful method to directly transform elements in a collection while iterating over them. This is one of the most important Ruby methods to learn. Here's an example:

def array_doubler(array)
  array.map { |a| a*2 }
end

reduce(): Reduce the elements in a collection to a single result. This is another extremely powerful and important Ruby method. For example:

[1,2,3].reduce(:+)
=> 6

reject(): Rejects elements from a collection that match a given condition. For example:

range.reject { |r| r > 5 }
=> [1, 2, 3, 4, 5]

select(): Grab all elements from a collection that match a given condition. Here's an example:

range = 1..10
range.select { |r| r > 5 }
=> [6, 7, 8, 9, 10]

Lesson 17 of 22
Last updated August 7, 2022