Ruby/RoR - Count occurrence of an element in an array

Simpler:

hash.values.count(true)

array.flatten.count(true)

This works with all the above cases.


In order to count the elements, you obviously have to iterate over the collection. Since iterating over a Hash yields two-element Arrays, the first two are actually exactly the same:

{ 1 => true, 7 => false, 6 => true, 4 => false }.count(&:last)
[[1, true], [7, false], [6, true], [4, false]].count(&:last)

For the simple Array case, you could do something like this:

[true, false, true, false].count(true)

This Array is of course also the same as the Hash#values from your Hash above, so you could use the same method on that:

{ 1 => true, 7 => false, 6 => true, 4 => false }.values.count(true)

If you don't know which one of three you will get, you could use something like this:

{ 1 => true, 7 => false, 6 => true, 4 => false }.flatten.count(true)
[[1, true], [7, false], [6, true], [4, false]].flatten.count(true)
[true, false, true, false].flatten.count(true)

With Enumerable#count:

hash.values.count(true)
array_of_pairs.map { |k, v| v }.count(true)
plain_array.count(true)

More verbose, but does not create intermediate arrays:

hash_or_array_of_pairs.inject(0) { |acc, (k, v)| acc + (v == true ? 1 : 0) }

Ruby 2.7+

Ruby 2.7 is introducing Enumerable#tally (and possibly tally_by) for this exact purpose. There's a good summary here.

There's a discussion about whether the final implementation will use tally or tally_by when providing a block, as here.

In this use case:

# or hash.tally_by if that's the accepted method for block form
hash.tally { |k, v| v }
# => { true => 2, false => 2 }

Docs on the features being released are here.

Hope this helps someone!