Reputation: 51292
I'v a hash
{1=>true, 7=>false, 6=>true, 4=>false}
or an array like
[1, true], [7, false], [6, true], [4, false]]
or
[true, false, true, false]
.
How can I find the number of true
s in the array?
Upvotes: 21
Views: 16507
Reputation: 401
Hash:
my_hash.values.select(&:present?).size
2D array:
my_2d_array.map(&:last).select(&:present?).size
or
my_2d_array.select { |_first, last| last.present? }.size
1D array:
array.select(&:present?).size
Upvotes: 0
Reputation: 1676
I'm trying to provide a more general answer: count the amount of each element. I'm still using 2.6.6
, so somebody else also has no 2.7.x
.
Preparation:
values_of_hash = {1=>true, 7=>false, 6=>true, 4=>false}.values # also works with the `.map` command from the line below
values_of_array_of_pairs = [[1, true], [7, false], [6, true], [4, false]].map { |k, v| v } # or the `.inject` command from this answer: https://stackoverflow.com/a/4488905/4575793
values_of_2d = [[1, true], [7, false], [6, true], [4, false]].map(&:last) # similar idea from https://stackoverflow.com/a/4490032/4575793
values_of_2d = {1=>true, 7=>false, 6=>true, 4=>false}.map(&:last) # both a hash and an array of pairs hold the second value in `.last`
values_of_array = [true, false, true, false]
Now you can just use
def my_tally(values)
Set.new(values).map {|unique_value| [unique_value, values.count(unique_value)]}
end
# replace `_xy` with anything of the above like e.g. `_array`
my_tally values_of_xy
# => [[true, 2], [false, 2]]
That also works for arbitrary data. Maybe you want to analyse this:
values_of_xy = {1=>:banana, 2=>:cherry, 3=>:apple, 4=>:cherry, 5=>:banana, 6=>:cherry}.values
my_tally values_of_xy
# => [[:banana, 2], [:cherry, 3], [:apple, 1]]
For Ruby 2.7+, you should obviously use tally.
Upvotes: 0
Reputation: 12213
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!
Upvotes: 5
Reputation: 67900
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) }
Upvotes: 7
Reputation: 369614
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)
Upvotes: 29
Reputation: 37527
Simpler:
hash.values.count(true)
array.flatten.count(true)
This works with all the above cases.
Upvotes: 4
Reputation: 32067
One way (your hash would need .to_a
called on it first for this to work on it):
[[1, true], [7, false], [6, true], [4, false]].flatten.select{|s| s == true }.size
Upvotes: 1
Reputation: 1739
For hashes:
{ :a => true, :b => true, :c => false }.select{ |k,v| v }.length
=> 2
For arrays:
[true, false, false, true, true].select{ |o| o }.length
=> 3
Another way (testing with a negation):
[true, false, false, true, true].reject{ |o| o != true }.length
=> 3
Upvotes: 2