Ruby: Enumerable Methods
Ruby's Enumerable class methods are included in enumerable objects, such as the common Array and Hash object types. It may help to remember that enumerable means countable. As such, enumerable objects are classified as such because they are collections of data, rather than being simply an object of a simple datatype. Enumerable methods provide functionality for accessing, selecting, and iterating through this collection-like datatype.
These methods introduce a new concept provided in the Ruby language -- the block (i.e. a block of code). Blocks are used to use a method as a method parameter. As shown here, many Enumerable methods accept a block as its parameter, and the block, in some way, accepts an enumerable's data member as a parameter. Each member of the enumerable gets processed by the block in turn.
Enumerable.each
Enumerable.each exposes each element of an enumerable to some programmer defined method. This method is used for its side effects, rather than for its return value. That is to say, for each element do something. It returns the object on which it was invoked.
A well-versed Rubyist may recognize that each is not a method defined within the Enumerable class, but rather a required method for any Object class which goes onto include or inherit the Enumerable class methods. The other Enumerable methods use each in their underlying implementation. That being said, each is a staple method in its own right.
ENUMERABLE.EACH[1,2,3].each do |number|
puts number
end
1
2
3
For Loop
Another common construct to access each element of an enumerable is Ruby's For loop. Similar to each, this construct exposes each member element of the object for processing. This is an alternative writing style to each for performing iterative processing through enumerable elements. The developer's decision on which to use is dependent on use case.
FOR OBJECT IN ENUMERABLEfor number in [1,2,3]
puts number
end
1
2
3
Enumerable.map
Enumerable.map takes a code block and processes each element of an enumerable then, without modifying the original object, returns a new Array with the block's return values in the position of the element which was processed. Use map rather than each when a return value is required.
ENUMERABLE.MAParray = [1,2,3].map do |number|
number * 2
end
print array
[2,4,6]
Enumerable.reduce
Enumerable.reduce is used to reduce an enumerable to a single data value. Similar to each and map, reduce requires a block of code to accomplish the processing, but unlike the other methods, reduce requires an initial value parameter. The code block takes the accumulated value as its first argument and the current element of consideration as its second.
During each iteration of the reduce loop, the value is being accumulated must be the return value of the code block, and that value is used as the first parameter of the next iteration of the code block. After the final iteration, the final accumulated value is returned to the outer scope.
ENUMERABLE.REDUCEsides = [1, 2, 2]
volume = sides.reduce(1) do |acc, number|
acc * number
end
puts volume
4
This example shows how one might calculate the volume of a three-dimensional box. Notice the initial value of is 1 used directly after the reduce keyword. That initial value is used as the first iteration's acc (accumulator) value. On subsequent invocations of the code block, the return value of the previous invocation becomes the acc value.
The initial value should be a careful decision based on use case. For example, if the requirement of the method was to sum the sides of the box, an initial value of 0 should be used. Further, if elements of the array were Strings and a String result was desired, the initial value would likely be a String.
Enumerable.filter
Enumerable.filter takes a code block and processes each element of an enumerable and, without modifying the original object, returns a subset of the original object with elements for which the code block returns true. The code block's return value should be some Boolean.
ENUMERABLE.FILTERsizes = [1,2,3,5,8]
large = sizes.filter do |number|
number > 3
end
print large
[5,8]
Enumerable.slice
Enumerable.slice returns some subset of the original Object. The slice method is an example of a method which is implemented differently for Objects which extend the Enumerable class. If the Object is an Array, the method signature takes the index at which to begin the slice, and the count of objects to take as the first and second parameters, respectively.
ARRAY.SLICEprint [0,1,2,3,4].slice(0,2)
[0,1]
If the Object is a Hash, slice takes as its parameters a list of keys which are to be selected from the Object.
HASH.SLICEhash = { name: 'Bob', age: 16, city: 'NYC' }
print hash.slice(:name, :city)
{ name: 'Bob', city: 'NYC' }
Further on Enumerables
The Enumerable class methods are for processing collections of data. A developer's use case ranges from sorting the elements, to finding one or some elements in the collection which satisfy some condition, to processing each member element and returning a new data object. The more than 40 methods provided by Enumerable are exemplified in the Appendix of this text.