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 Array
s, 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!