开发者

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

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 trues in the array?


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) }


Simpler:

hash.values.count(true)

array.flatten.count(true)

This works with all the above cases.


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!


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


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜