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. |
very, very handy. i’d like to an ‘enumerable from first principles’ using only inject to recreate every other one.
http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&item=140457499974&ssPageName=STRK:MESELX:IT