6

I can count a value using Array#count.

numbers = [1, 2, 5, 5, 1, 3, 1, 2, 4, 3]
numbers.count(1) #=> 3

How can I count multiple values in an array?

What I wrote were:

numbers.count(1) + numbers.count(2) #=> 5
[1,2].map{|i| numbers.count(i)}.sum #=> 5

I think these are a bit redundant.

2
  • Possible duplicate of Ruby: Count unique elements and their occurences in an array Commented May 13, 2016 at 2:49
  • 1
    The question nominated as an exemplar is similar, but not a proper duplicate: That question asks how to find the count of each distinct element, whereas this question asks for the sum of the counts of selected elements. Commented May 13, 2016 at 3:26

3 Answers 3

7

count can also take a block, so you can write this in a way that only traverses the array once:

numbers.count {|i| [1,2].include? i } # => 5

Or for fun, in a slightly more functional/point-free style:

numbers.count &[1,2].method(:include?) # => 5
Sign up to request clarification or add additional context in comments.

Comments

2

You mean something pretty like this?

[1, 2, 2, 3, 3, 3, 4, 4, 4, 4].count_all(3, 4) # => 7

While there's nothing in Ruby's core library that provides that functionality directly, it's pretty trivial to add it.

You could just write helper method:

def count_all(array, values_to_count)
  array.count { |el| values_to_count.include?(el) }
end

count_all([1, 2, 2, 3, 3, 3, 4, 4, 4, 4], [3, 4]) # => 7

You could instead use Ruby's new refinements to add a method to Array when you need it:

module ArrayExtensions
  refine Array do
    def count_all(*values_to_count)
      self.count { |el| values_to_count.include?(el) }
    end
  end
end

# Then inside some module or class

using ArrayExtensions

[1, 2, 2, 3, 3, 3, 4, 4, 4, 4].count_all(3, 4) # => 7

Or you could opt to take the more hacky path and modify Array directly:

class Array
  def count_all(*values_to_count)
    self.count { |el| values_to_count.include?(el) }
  end
end

[1, 2, 2, 3, 3, 3, 4, 4, 4, 4].count_all(3, 4) # => 7

Comments

1
numbers = [1, 2, 5, 5, 1, 3, 1, 2, 4, 3]
numbers_to_count = [1, 2]

numbers.size - (numbers - numbers_to_count).size
  #=> 5

We have

n = numbers.size
  #=> 10 
a = (numbers - numbers_to_count)
  #=> [5, 5, 3, 4, 3] 
m = a.size
  #=> 5 
n - m
  #=> 5

require 'fruity'

n = 1e6
numbers = Array.new(n) { rand(100) }
  #=> [21, 78, 20, 98,..., 41, 87, 57] 
numbers.size
  #=> 1000000
numbers_to_count = (0..99).to_a.sample(20)
  #=> [80, 61, 43, 84, 16, 65, 7, 98, 59, 6,
  #    58, 49, 1, 9, 94, 56, 13, 67, 22, 68]     

compare do 
  _jtb1 { numbers.count {|i| numbers_to_count.include? i } }
  _jtb2 { numbers.count &numbers_to_count.method(:include?) }
  _cary { numbers.size - (numbers - numbers_to_count).size }
end

Running each test once. Test will take about 9 seconds.
_cary is faster than _jtb1 by 5x ± 1.0
_jtb1 is faster than _jtb2 by 10.000000000000009% ± 10.0%

This is not surprising considering that Array#- is coded in C.

I didn't benchmark @faraz's methods as they appear to be similar to @jtbandes'.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.