The Enumerable module in Ruby contains a special collection of methods for hash and array classes. In this guide, we will briefly discuss some of the most common methods in the module and how to use them. In addition, the bonus section at the end of this guide will give you a couple tips on how to write your own enumerable methods.
The each method passes each element of an array to the block you specified, using the format each { |obj| block }
. The method returns the original collection that it was called on.
Example:
The following code displays each element of an array on a separate line.
[1, 2, 3].each { |x| puts x } #=>
1
2
3
A related method is each_with_index, which takes both the object and its index as arguments and pass them through the block you specified.
Example:
The following code displays each element whose index is odd.
fruits.each_with_index { |item, index| print "{#item}" if index%2 != 0 } #=>
[Apple, Orange]
The select method returns an array with elements for which the given block returns true.
Example:
The following code returns a new array with the even numbers from the original array.
my_array.select { |num| num%2 == 0 } #=> [2, 4, 6, 8]
A related method is reject, which is basically the opposite of select. Reject returns a new array with elements from the original for which the given block returns false.
Example:
The following code returns an array containing only odd numbers.
my_array = [1, 2, 3, 4, 5, 6, 7, 8]
my_array.reject { |num| num%2 == 0 } #=> [1, 3, 5, 7]
The map and collect methods have the same function, they return a new array containing the results of elements modified by the given block.,/p>
Example:
The following code returns an array with numbers 1-10 multiplied by 2.
1..10.map { |i| i * i } #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
The all? method returns true when all array satisfies the given condition.
Example:
Returns true if all numbers are less than 1.
1..4.all? { |num| num < 10 } #=> true
The none? method returns true if none of the elements in the array satisfies the given condition.
Example:
Returns true if no number is greater than 10.
1..4.none? { |num| num > 10 } #=> true
The any? method returns true if any of the elements satisfies the given condition.
Example:
Returns true if the array contains even numbers.
1..4.any? { |x| x <= 0 } #=> true
Just like the collect and map methods, the inject and reduce methods have the same function. They gather up the elements of an array into a single value based on some pattern. In each iteration, the current element and an accumulator value is passed to the block. If you specify a symbol, such as (+, -, *, /, etc.), the accumulator value and the current element will be passed to a method that returns the result of the accumulator and the current element modified by the symbol. This value then becomes the new value of the accumulator. To specify an initial value, place it in parentheses before the block, otherwise the first value will be used as the initial value.
Example:
Returns the result of adding numbers one thru 8.
1..8.inject(0) { |total, item| total + item } #=> 45
The yield keyword. All the methods we discussed so far rely on the method 'each' to bring out each element in an array, in order for other methods to display, select, or modify those that fit certain criteria. For 'each' and all the other methods that require passing code to blocks, the yield keyword is crucial. In short, yield tells the program when to call the block and pass the current object to it.
Example:
This is an implementation of the each method, called my_each.
def my_each
i = 0
while i < self.size do
yield(self[i])
i += 1
end
self
end
The &block. Although blocks are very useful, they don't have names, which limits us to running it once through each iteration. If we want to be able to call a block whenever we want, the &block gives us a way to do so. The &block allows us to capture our block into a callback that we can then pass to a method.
Example
In the following implementation of my_inject, the previous result for each iteration is retrieved through a callback to block. This value, along with the current element, is then passed to the block and the result is updated.
def my_inject(result = nil, &block)
accumulator = 0 if accumulator == nil
result = self[accumulator]
i = accumulator + 1
while i < self.size do
result = block.call(result, self[i])
i += 1
end
result
end
As we have seen, the Enumerable module is filled with many useful methods. Some of those we have not cover include
According to the documentation for Ruby 2.5.1, there are 55 methods in Enumerable. If you have time, definitely check them out!