Menu

Back Home

Harnessing Ruby Enumerable

You’re probably afraid to ask about some of the methods in the Ruby Enumerable mixin. Not only are there a whole bunch of them, 41 in Ruby 1.9 to be exact, but selecting the right one for the problem can be an exercise in frustration. Part of the problem is there’s no easy way to identify what method might suit your requirements. While the names are usually self-explanatory, it can be tricky to remember block arguments or if they return an Array or a particular element.

Any toolbox needs to be organized, so it’s probably best to sort the various Enumerable methods into groups based on the kind of result you want to get. Grouped together like this, the methodology within Ruby becomes more apparent.

Conventions

In this description, “true / false” refers to values that are equivalent to true, or equivalent to false. In practical terms this means that nil and false are both considered false, and everything else is non-false, (or in general terms, true). Note: things that evaluate as true include what might be considered false in other languages such as 0, empty strings, and empty Array or Hash structures.

When describing the blocks, e refers to an element in the set. For an Array, this is simply the element at a particular index. For a Hash this is a key/value pair, so the block semantics should be expanded to { |(k,v)| } or e.first and e.last will need to be used within the block.

Assessment

One of the simplest features of Enumerable is the methods that provide a quick true/false assessment based on the content involved. Often these will be used to decide how to handle an Array or Hash, or if its in a condition that can be utilized.

Method Arguments Block Definition Return
all? { |e| … } => true / false
* Optional
true / false
Runs each element through the given block with and returns true if all of the block results evaluate true, otherwise false. Without a block returns true if all the elements evaluate as true, otherwise false.
any? { |e| … } => true / false
* Optional
true / false
Runs each element through the given block with and returns true if any of the block results evaluate true, otherwise false. Without a block returns true if any the elements evaluate as true, otherwise false.
none? { |e| … } => true / false
* Optional
true / false
Runs each element through the given block with and returns true if none of the block results evaluate true, otherwise false. Without a block returns true if none the elements evaluate as true, otherwise false.
one? { |e| … } => true / false
* Optional
true / false
Runs each element through the given block with and returns true if one of the block results evaluate true, otherwise false. Without a block returns true if one the elements evaluate as true, otherwise false.

Single Element

Often you’ll want to extract a single element from a set. In this case there are many ways to get what you want, each with their particular quirks.

Method Arguments Block Definition Return
detect ifnone = nil { |e| … } => true / false element / nil
Runs each element through the given block with and returns the first element for which the block result is true. If all return false, the result is nil.
find ifnone = nil { |e| … } => true / false element / nil
The same as detect, this runs each element through the given block with and returns the first element for which the block result is true. If all return false, the result is nil.
first element / nil
Returns the first element in the set, of if the set is empty then nil.
max { |a,b| … } => -1 / 0 / 1
* Optional
element / nil
Returns the largest element in the set, of if the set is empty then nil. The result of the optional block should be compatible with Comparable and return -1, 0, or 1.
max_by { |e| … } element / nil
Returns the largest element in the set where comparisons are performed on the result of the block, of if the set is empty then nil. Anything returned by the block must be compatible with Comparable.
min { |a,b| … } => -1 / 0 / 1
* Optional
element / nil
Returns the smallest element in the set, of if the set is empty then nil. The result of the optional block should be compatible with Comparable and return -1, 0, or 1.
min_by { |e| … } element / nil
Returns the smallest element in the set where comparisons are performed on the result of the block, of if the set is empty then nil. Anything returned by the block must be compatible with Comparable.

Filtering

Method Arguments Block Definition Return
grep regexp { |e| … }
* Optional
Array
Matches each element against the supplied regexp and returns all that match in an Array. If a block is supplied, all matching elements are transformed by the block before being inserted into the result Array, which avoids having to chain the result through a map call.
reject { |e| … } => true / false Array
Runs all elements through the supplied block and excludes those from the result array where the block evaluates as true.
select { |e| … } => true / false Array
The inverse of , this runs all elements through the supplied block and includes those from the result array where the block evaluates as true.
select { |e| … } => true / false Array
The inverse of , this runs all elements through the supplied block and includes those from the result array where the block evaluates as true.

Transformation

There are a few powerful methods for transforming the content of one set into an Array.

Method Arguments Block Definition Return
collect { |e| … } Array
Runs each element through the provided block and puts each block result in the Array that is returned.
map { |e| … } Array
The same as collect, runs each element through the provided block and puts each block result in the Array that is returned.
inject memo = first { |memo, e| … } last block result / nil
This is perhaps the most understood and under-utilized method in the Enumerable toolkit. In general terms, this method takes a seed “memo” value, and runs that through the block in conjunction with each element. The result of the first block call is supplied to the second, and so on, which leaves the door wide open as to what this method can do. For instance, every other Enumerable method can be expressed as a form of inject.

2 Responses to Harnessing Ruby Enumerable

  1. georges says:

    very, very handy. i’d like to an ‘enumerable from first principles’ using only inject to recreate every other one.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>