Enumerating Enumerable: Enumerable#find_all / Enumerable#select

by Joey deVilla on August 7, 2008

Enumerating Enumerable

We’re at lucky number 13 — the thirteenth article in the Enumerating Enumerable series, which covers the methods of Ruby’s Enumerable module. I started this series after being disappointed with the documentation at Ruby-Doc.org.

In this article, I’m covering the find_all — a.k.a. select — method.

In case you missed any of the previous articles, they’re listed and linked below:

  1. all?
  2. any?
  3. collect / map
  4. count
  5. cycle
  6. detect / find
  7. drop
  8. drop_while
  9. each_cons
  10. each_slice
  11. each_with_index
  12. entries / to_a

Enumerable#find_all / Enumerable#select Quick Summary

Graphic representation of the \"find_all\" / \"select\" method in Ruby\'s \"Enumerable\" module

In the simplest possible terms Which items in the collection meet the given criteria?
Ruby version 1.8 and 1.9
Expects A block containing the criteria.
Returns An array containing the items in the collection that meet the given criteria. If no items in the collection meet the given criteria, this is an empty array.
RubyDoc.org’s entry Enumerable#find_all / Enumerable#select

Enumerable#find_all / Enumerable#select and Arrays

When used on an array, find_all and its synonym select passes each item from the array to the block, returning an array containing only those elements in the original array for which the block returns a value that doesn’t evaluate to false.

If no item in the array causes the block to return a value that doesn’t evaluate to false, find_all/select returns an empty array.

In the examples that follow (which are based on my examples for the detect/find method), I’ll be using the find_all method. select does exactly the same thing; it’s just that I prefer find_all.

# Once again,  I shall establish my "old fart" credentials
classic_rock_bands = ["AC/DC", "Black Sabbath", "Queen", \
"Ted Nugent and the Amboy Dukes", "Scorpions", "Van Halen"]
=> ["AC/DC", "Black Sabbath", "Queen", "Ted Nugent and the Amboy Dukes",
"Scorpions", "Van Halen"]

# Of the bands in the array, which ones have
# a name longer than 8 characters?
classic_rock_bands.find_all {|band| band.length > 8}
=> ["Black Sabbath", "Ted Nugent and the Amboy Dukes", "Scorpions", "Van Halen"]

# Which ones have a name exactly 5 characters long?
classic_rock_bands.find_all {|band| band.length == 5}
=> ["AC/DC", "Queen"]

# If no band in the array meets the criteria,
# find_all returns an empty array.
# Which ones have names shorter than 5 characters?
classic_rock_bands.find_all {|band| band.length < 5}
=> []

Enumerable#find_all / Enumerable#select and Hashes

When used on a hash, find_all/select passes each key/value pair in the hash to the block, which you can “catch” as either:

  1. A two-element array, with the key as element 0 and its corresponding value as element 1, or
  2. Two separate items, with the key as the first item and its corresponding value as the second item.

As with arrays, find_all/select passes each item from the hash to the block, returning an array containing only those items in the original array for which the block returns a value that doesn’t evaluate to false.

Note that each item in the result array is a two-element array corresponding to an item from the original hash. In this array, element 0 contains the key and element 1 contains the corresponding value.

If no item in the hash causes the block to return a value that doesn’t evaluate to false, find_all/select returns an empty array.

years_founded = {"AC/DC" => 1973, \
                 "Black Sabbath" => 1968, \
                 "Queen" => 1970, \
                 "Ted Nugent and the Amboy Dukes" => 1967, \
                 "Scorpions" => 1965, \
                 "Van Halen" => 1972}
=> {"AC/DC"=>1973, "Black Sabbath"=>1968, "Queen"=>1970,
"Ted Nugent and the Amboy Dukes"=>1967, "Scorpions"=>1965, "Van Halen"=>1972}

# Ruby 1.9 preserves hash order so that hashes keep the order in which
# you defined them, while Ruby 1.8 puts them in some mysterious order.
# All these examples are in Ruby 1.9

# Which bands were founded in 1970 or later?
years_founded.find_all {|band| band[1] >= 1970}
=> [["AC/DC", 1973], ["Queen", 1970], ["Van Halen", 1972]]

# Here's another way of phrasing it:
years_founded.find_all {|band, year_founded| year_founded >= 1970}
=> [["AC/DC", 1973], ["Queen", 1970], ["Van Halen", 1972]]

# Which bands were founded after 1980?
years_founded.find_all {|band, year_founded| year_founded > 1980}
=> []

Previous post:

Next post: