如何计算数组中的多个值

时间:2021-01-26 15:41:45

I can count a value using Array#count.

我可以使用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.

我认为这些有点多余。

3 个解决方案

#1


7  

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

count也可以占用一个块,所以你可以用只遍历数组的方式写一次:

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

#2


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.

虽然Ruby的核心库中没有直接提供该功能的东西,但添加它是非常简单的。

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:

您可以使用Ruby的新改进在需要时向Array添加方法:

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:

或者您可以选择采用更多hacky路径并直接修改Array:

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

#3


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.

考虑到Array# - 用C编码,这并不奇怪。

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

我没有对@ faraz的方法进行基准测试,因为它们似乎与@jtbandes类似。

#1


7  

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

count也可以占用一个块,所以你可以用只遍历数组的方式写一次:

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

#2


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.

虽然Ruby的核心库中没有直接提供该功能的东西,但添加它是非常简单的。

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:

您可以使用Ruby的新改进在需要时向Array添加方法:

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:

或者您可以选择采用更多hacky路径并直接修改Array:

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

#3


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.

考虑到Array# - 用C编码,这并不奇怪。

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

我没有对@ faraz的方法进行基准测试,因为它们似乎与@jtbandes类似。