The raison d’etre
While I often refer to the documentation at Ruby-Doc.org, I often find its descriptions a little unclear, lacking in detail and even missing some vital information. In the “do it yourself and share it afterwards” spirit of Open Source, I’ve decided to start working on a series of articles that I’ll eventually compile into a single site to become a useful, complete and better alternative to Ruby-Doc.org’s docs. These articles will appear here on Global Nerdy on an ongoing basis, and I hope you’ll find them useful.
My plan is to start with a module whose methods you’re guaranteed to use in your day-to-day Ruby development: Enumerable
, a mixin that adds traversal, search, filtering and sorting functionality to collection classes, including those workhorses known as Array and Hash. My articles on Enumerable
‘s methods should fill in some holes Ruby-Doc.org’s coverage (especially for hashes, which gets surprisingly little coverage). I’ll be going through Enumerable
‘s methods alphabetically.
In this installment, I’ll cover two of Enumerable
‘s methods: all?
and any?
all?
- In plain language: Do all the items in the collection meet the given criteria?
- Ruby.Doc.org’s entry:
Enumerable#all?
- Expects: A block containing the criteria (it’s optional, but you’re likely to use one most of the time).
- Returns:
true
if all the items in the collection meet the given criteriafalse
otherwise
Using all?
with Arrays
When used on an array and a block is provided, all?
passes each item to the block. If the block never returns false
or nil
during this process, all?
returns true
; otherwise, it returns false
.
# "feta" is the shortest-named cheese in this list cheeses = ["feta", "cheddar", "stilton", "camembert", "mozzarella", "Fromage de Montagne de Savoie"] cheeses.all? {|cheese| cheese.length >= 4} => true cheeses.all? {|cheese| cheese.length >= 5} => false
When the block is omitted, all?
uses this implied block: {|item| item}
. Since everything in Ruby evaluates to true
except for false
and nil
, using all?
without a block is effectively a test to see if all the items in the collection evaluate to true
(or conversely, if there are any false
or nil
values in the array).
cheeses.all? => true cheeses << false => ["feta", "cheddar", "stilton", "camembert", "mozzarella", "Fromage de Montagne de Savoie", false] cheeses.all? => false
Using all?
with Hashes
When used on a hash and a block is provided, all?
passes each key/value pair in the hash to the block, which you can “catch” as either:
- A two-element array, with the key as element 0 and its corresponding value as element 1, or
- Two separate items, with the key as the first item and its corresponding value as the second item.
If the block never returns false
or nil
during this process, all?
returns true
; otherwise, it returns false
.
# Here's a hash where for each key/value pair, the key is a programming language and # the corresponding value is the year when that language was first released # The keys range in value from "Javascript" to "Ruby", and the values range from # 1987 to 1996 languages = {"Javascript" => 1996, "PHP" => 1994, "Perl" => 1987, "Python" => 1991, "Ruby" => 1993} languages.all? {|language| language[0] >= "Delphi"} => true languages.all? {|language, year_created| language >= "Delphi"} => true languages.all? {|language| language[0] >= "Visual Basic"} => false languages.all? {|language, year_created| language >= "Visual Basic"} => false languages.all? {|language| language[0] >= "Delphi" and language[1] <= 2000} => true languages.all? {|language, year_created| language >= "Delphi" and year_created <= 2000} => true languages.all? {|language| language[0] >= "Delphi" and language[1] > 2000} => false languages.all? {|language, year_created| language >= "Delphi" and year_created > 2000} => false
Using all?
without a block on a hash is meaningless, as it will always return true
. When the block is omitted, all?
uses this implied block: {|item| item}
. In the case of a hash, item
will always be a two-element array, which means that it will never evaluate as false
nor nil
.
And yes, even this hash, when run through all?
, will still return true
:
{false => false, nil => nil}.all? => true
Special Case: Using all?
on Empty Arrays and Hashes
When applied to an empty array or hash, with or without a block, all?
always returns true
.
Let’s look at the case of empty arrays:
cheeses = [] => [] cheeses.all? {|cheese| cheese.length >= 4} => true cheeses.all? => true # Let's try applying "all?" to a non-empty array # using a block that ALWAYS returns false: ["Gruyere"].all? {|cheese| false} => false # ...but watch what happens when we try the same thing # with an EMPTY array! [].all? {|cheese| false} => true
…now let’s look at the case of empty hashes:
languages = {} => {} languages.all? {|language| language[0] >= "Delphi"} => true languages.all? {|language, year_created| language >= "Delphi"} => true languages.all? => true # Let's try applying "all?" to a non-empty hash # using a block that ALWAYS returns false: {"Lisp" => 1959}.all? {|language| false} => false # ...but watch what happens when we try the same thing # with an EMPTY hash! {}.all? {|language| false} => true
any?
- In plain language: Do any of the items in the collection meet the given criteria?
- Ruby.Doc.org’s entry:
Enumerable#any?
- Expects: A block containing the criteria (it’s optional, but you’re likely to use one most of the time).
- Returns:
true
if any of the items in the collection meet the given criteriafalse
otherwise
Using any?
with Arrays
When used on an array and a block is provided, any?
passes each item to the block. If the block returns true
for any item during this process, any?
returns true
; otherwise, it returns false
.
# "Fromage de Montagne de Savoie" is the longest-named cheese in this list # at a whopping 29 characters cheeses = ["feta", "cheddar", "stilton", "camembert", "mozzarella", "Fromage de Montagne de Savoie"] cheeses.any? {|cheese| cheese.length >= 25} => true cheeses.any? {|cheese| cheese.length >= 35} => false
When the block is omitted, any?
uses this implied block: {|item| item}
. Since everything in Ruby evaluates to true
except for false
and nil
, using any?
without a block is effectively a test to see if any of the items in the collection evaluate to true
(or conversely, if all the values in the array evaluate to false
or nil
).
cheeses.any? => true cheeses = [false, nil] => [false, nil] cheeses.any? => false # Remember that in Ruby, everything except for false and nil evaluates to true: cheeses << 0 => [false, nil, 0] >> cheeses.any? => true
Using any?
with Hashes
When used on a hash and a block is provided, any?
passes each key/value pair in the hash to the block, which you can “catch” as either:
- A two-element array, with the key as element 0 and its corresponding value as element 1, or
- Two separate items, with the key as the first item and its corresponding value as the second item.
If the block returns true
for any item during this process, any?
returns true
; otherwise, it returns false
.
# Here's a hash where for each key/value pair, the key is a programming language and # the corresponding value is the year when that language was first released # The keys range in value from "Javascript" to "Ruby", and the values range from # 1987 to 1996 languages = {"Javascript" => 1996, "PHP" => 1994, "Perl" => 1987, "Python" => 1991, "Ruby" => 1993} languages.any? {|language| language[0] < "Pascal"} => true languages.any? {|language, year_created| language < "Pascal"} => true languages.any? {|language| language[0] < "Fortran"} => false languages.any? {|language, year_created| language < "Fortran"} => false languages.any? {|language| language[0] >= "Basic" and language[1] <= 1995} => true languages.any? {|language, year_created| language >= "Basic" and year_created <= 1995} => true languages.any? {|language| language[0] >= "Basic" and language[1] <= 1985} => false languages.any? {|language, year_created| language >= "Basic" and year_created <= 1985} => false
Using any?
without a block on a hash is meaningless, as it will always return true
. When the block is omitted, any?
uses this implied block: {|item| item}
. In the case of a hash, item
will always be a two-element array, which means that it will never evaluate as false
nor nil
.
And yes, even this hash, when run through any?
, will still return true
:
{false => false, nil => nil}.any? => true
Special Case: Using any?
on Empty Arrays and Hashes
When applied to an empty array or hash, with or without a block, any?
always returns false
.
Let’s look at the case of empty arrays:
cheeses = [] => [] cheeses.any? {|cheese| cheese.length >= 25} => false cheeses.any? => false # Let's try applying "any?" to a non-empty array # using a block that ALWAYS returns true: ["Gruyere"].any? {|cheese| true} => true # ...but watch what happens when we try the same thing # with an EMPTY array! [].any? {|cheese| true} => false
…now let’s look at the case of empty hashes:
languages = {} => {} languages.any? {|language| language[0] < "Pascal"} => false languages.any? {|language, year_created| language < "Pascal"} => false languages.any? => false # Let's try applying "any?" to a non-empty hash # using a block that ALWAYS returns true: {"Lisp" => 1959}.any? {|language| true} => true # ...but watch what happens when we try the same thing # with an EMPTY hash! {}.any? {|language| true} => false
In the Next Installment…
…the collect
(a.k.a. map
) method.
4 replies on “Enumerating Ruby’s “Enumerable” Module, Part 1: “all?” and “any?””
[…] In the last article in this series covering the methods in Ruby’s Enumerable module, I covered all? and any?. In this installment, I’ll look at the collect method, a.k.a. the map method. […]
[…] all? and any? […]
[…] http://www.globalnerdy.com/2008/01/29/enumerating-rubys-enumerable-module-part-1-all-and-any/ […]
[…] http://www.globalnerdy.com/2008/01/29/enumerating-rubys-enumerable-module-part-1-all-and-any/ […]