Welcome to the fourth installment of Enumerating Enumerable , a series of articles in which I challenge myself to do a better job of documenting Ruby’s Enumerable module than RubyDoc.org does. In this article, I’ll cover Enumerable#count , one of the new methods added to Enumerable in Ruby 1.9.

In case you missed the earlier installments, they’re listed (and linked) below:

Enumerable#count Quick Summary

In the simplest possible terms How many items in the collection meet the given criteria? Ruby version 1.9 only Expects Either: An argument to be matched against the items in the collection

A block containing an expression to test the items in the collection Returns The number of items in the collection that meet the given criteria. RubyDoc.org’s entry Enumerable#count

Enumerable#count and Arrays

When used on an array and an argument is provided, count returns the number of times the value of the argument appears in the array:

# How many instances of "zoom" are there in the array? ["zoom", "schwartz", "profigliano", "zoom"].count("zoom") => 2 # Prior to Ruby 1.9, you'd have to use this equivalent code: ["zoom", "schwartz", "profigliano", "zoom"].select {|word| word == "zoom"}.size => 2 1 2 3 4 5 6 7 # How many instances of "zoom" are there in the array ? [ "zoom" , "schwartz" , "profigliano" , "zoom" ] . count ( "zoom" ) = > 2 # Prior to Ruby 1.9 , you ' d have to use this equivalent code : [ "zoom" , "schwartz" , "profigliano" , "zoom" ] . select { | word | word == "zoom" } . size = > 2

When used on an array and a block is provided, count returns the number of items in the array for which the block returns true :

# How many members of "The Mosquitoes" (a Beatles-esque band that appeared on # "Gilligan's Island") have names following the "B*ngo" format? ["Bingo", "Bango", "Bongo", "Irving"].count {|bandmate| bandmate =~ /B[a-z]ngo/} => 3 # Prior to Ruby 1.9, you'd have to use this equivalent code: ["Bingo", "Bango", "Bongo", "Irving"].select {|bandmate| bandmate =~ /B[a-z]ngo/}.size 1 2 3 4 5 6 7 # How many members of "The Mosquitoes" ( a Beatles - esque band that appeared on # "Gilligan's Island" ) have names following the "B*ngo" format ? [ "Bingo" , "Bango" , "Bongo" , "Irving" ] . count { | bandmate | bandmate = ~ / B [ a - z ] ngo / } = > 3 # Prior to Ruby 1.9 , you ' d have to use this equivalent code : [ "Bingo" , "Bango" , "Bongo" , "Irving" ] . select { | bandmate | bandmate = ~ / B [ a - z ] ngo / } . size

RubyDoc.org says that when count is used on an array without an argument or a block, it simply returns the number of items in the array (which is what the length / size methods do). However, when I’ve tried it in irb and ruby, I got results like this:

[1, 2, 3, 4].count => #<Enumerable::Enumerator:0x189d784> 1 2 [ 1 , 2 , 3 , 4 ] . count = > # & lt ; Enumerable :: Enumerator : 0x189d784 & gt ;

Enumerable#count and Hashes

As with arrays, when used on a hash and an argument is provided, count returns the number of times the value of the argument appears in the hash. The difference is that for the comparison, each key/value pair is treated as a two-element array, with the key being element 0 and the value being element 1.

# Here's a hash where the names of recent movies are keys # and their metacritic.com ratings are the corresponding values. movie_ratings = {"Get Smart" => 53, "Kung Fu Panda" => 88, "The Love Guru" => 15, "Sex and the City" => 51, "Iron Man" => 93} => {"Get Smart"=>53, "Kung Fu Panda"=>88, "The Love Guru"=>15, "Sex and the City"=>51, "Iron Man"=>93} # This statement will return a count of 0, since there is no item in movie_ratings # that's just plain "Iron Man". movie_ratings.count("Iron Man") => 0 # This statement will return a count of 1, since there is an item in movie_ratings # with the key "Iron Man" and the corresponding value 93. movie_ratings.count(["Iron Man", 93]) => 1 # This statement will return a count of 0. There's an item in movie_ratings # with the key "Iron Man", but its corresponding value is NOT 92. movie_ratings.count(["Iron Man", 92]) => 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # Here 's a hash where the names of recent movies are keys # and their metacritic.com ratings are the corresponding values. movie_ratings = {"Get Smart" => 53, "Kung Fu Panda" => 88, "The Love Guru" => 15, "Sex and the City" => 51, "Iron Man" => 93} => {"Get Smart"=>53, "Kung Fu Panda"=>88, "The Love Guru"=>15, "Sex and the City"=>51, "Iron Man"=>93} # This statement will return a count of 0, since there is no item in movie_ratings # that' s just plain "Iron Man" . movie_ratings . count ( "Iron Man" ) = > 0 # This statement will return a count of 1 , since there is an item in movie_ratings # with the key "Iron Man" and the corresponding value 93 . movie_ratings . count ( [ "Iron Man" , 93 ] ) = > 1 # This statement will return a count of 0 . There ' s an item in movie_ratings # with the key "Iron Man" , but its corresponding value is NOT 92 . movie_ratings . count ( [ "Iron Man" , 92 ] ) = > 0

count is not useful when used with a hash and an argument. It will only ever return two values:

1 if the argument is a two-element array and there is an item in the hash whose key matches element [0] of the array and whose value matches element [1] of the array.

if the argument is a two-element array and there is an item in the hash whose key matches element [0] of the array and whose value matches element [1] of the array. 0 for all other cases.

When used with a hash and a block, count is more useful. count 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.

Each key/value pair is passed to the block and count returns the number of items in the hash for which the block returns true .

# Once again, a hash where the names of recent movies are keys # and their metacritic.com ratings are the corresponding values. movie_ratings = {"Get Smart" => 53, "Kung Fu Panda" => 88, "The Love Guru" => 15, "Sex and the City" => 51, "Iron Man" => 93} => {"Get Smart"=>53, "Kung Fu Panda"=>88, "The Love Guru"=>15, "Sex and the City"=>51, "Iron Man"=>93} # How many movie titles in the collection start # in the first half of the alphabet? # (Using a one-parameter block) movie_ratings.count {|movie| movie[0] <= "M"} => 3 # How many movie titles in the collection start # in the first half of the alphabet? # (This time using a two-parameter block) movie_ratings.count {|title, rating| title <= "M"} => 3 # Here's how you'd do it in pre-1.9 Ruby: movie_ratings.select {|movie| movie[0] <= "M"}.size => 3 # or... movie_ratings.select {|title, rating| title <= "M"}.size => 3 # How many movies in the collection had a rating # higher than 80? # (Using a one-parameter block) movie_ratings.count {|movie| movie[1] > 80} => 2 # How many movies in the collection had a rating # higher than 80? # (This time using a two-parameter block) movie_ratings.count {|title, rating| rating > 80} => 2 # Here's how you'd do it in pre-1.9 Ruby: movie_ratings.select {|title, rating| rating > 80}.size => 2 # How many movies in the collection have both: # - A title starting in the second half of the alphabet? # - A rating less than 50? # (Using a one-parameter block) movie_ratings.count {|movie| movie[0] >= "M" && movie[1] < 50} => 1 # How many movies in the collection have both: # - A title starting in the second half of the alphabet? # - A rating less than 50? # (This time using a two-parameter block) movie_ratings.count {|title, rating| title >= "M" && rating < 50} => 1 # Here's how you'd do it in pre-1.9 Ruby: movie_ratings.select {|title, rating| title >= "M" && rating < 50}.size => 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 # Once again , a hash where the names of recent movies are keys # and their metacritic . com ratings are the corresponding values . movie_ratings = { "Get Smart" = > 53 , "Kung Fu Panda" = > 88 , "The Love Guru" = > 15 , "Sex and the City" = > 51 , "Iron Man" = > 93 } = > { "Get Smart" = > 53 , "Kung Fu Panda" = > 88 , "The Love Guru" = > 15 , "Sex and the City" = > 51 , "Iron Man" = > 93 } # How many movie titles in the collection start # in the first half of the alphabet ? # ( Using a one - parameter block ) movie_ratings . count { | movie | movie [ 0 ] <= "M" } = > 3 # How many movie titles in the collection start # in the first half of the alphabet ? # ( This time using a two - parameter block ) movie_ratings . count { | title , rating | title <= "M" } = > 3 # Here 's how you' d do it in pre - 1.9 Ruby : movie_ratings . select { | movie | movie [ 0 ] <= "M" } . size = > 3 # or ... movie_ratings . select { | title , rating | title <= "M" } . size = > 3 # How many movies in the collection had a rating # higher than 80 ? # ( Using a one - parameter block ) movie_ratings . count { | movie | movie [ 1 ] > 80 } = > 2 # How many movies in the collection had a rating # higher than 80 ? # ( This time using a two - parameter block ) movie_ratings . count { | title , rating | rating > 80 } = > 2 # Here 's how you' d do it in pre - 1.9 Ruby : movie_ratings . select { | title , rating | rating > 80 } . size = > 2 # How many movies in the collection have both : # - A title starting in the second half of the alphabet ? # - A rating less than 50 ? # ( Using a one - parameter block ) movie_ratings . count { | movie | movie [ 0 ] >= "M" && movie [ 1 ] < 50 } = > 1 # How many movies in the collection have both : # - A title starting in the second half of the alphabet ? # - A rating less than 50 ? # ( This time using a two - parameter block ) movie_ratings . count { | title , rating | title >= "M" && rating < 50 } = > 1 # Here 's how you' d do it in pre - 1.9 Ruby : movie_ratings . select { | title , rating | title >= "M" && rating < 50 } . size = > 1