Ruby 查看数组中所有元素是否具有特定值的最快方法

Ruby 查看数组中所有元素是否具有特定值的最快方法,ruby,arrays,performance,Ruby,Arrays,Performance,我需要一种非常快速的方法来确定数组是否只包含值为9的整数。以下是我当前的解决方案: input = [9,9,9,9,9,9,9,9,9,9,9,9] input.uniq == [9] 你能做得更快吗?我想你的意思是input.uniq==[9],因为你实际上为我返回了false。你说的更快是什么意思?这段代码需要快速运行吗?我认为detect更快,因为它将返回与测试匹配的第一个元素: input = [9,9,9,9,9,9,9,9,9,9,9,9] input.detect { |i|

我需要一种非常快速的方法来确定数组是否只包含值为
9
的整数。以下是我当前的解决方案:

input = [9,9,9,9,9,9,9,9,9,9,9,9]
input.uniq == [9]

你能做得更快吗?

我想你的意思是
input.uniq==[9]
,因为你实际上为我返回了false。你说的更快是什么意思?这段代码需要快速运行吗?我认为detect更快,因为它将返回与测试匹配的第一个元素:

input = [9,9,9,9,9,9,9,9,9,9,9,9]
input.detect { |i| i != 9 }.nil?

您有几个选择:

>> input.count(9)==input.size
=> true


或者您上面的解决方案。

这将循环数组并在找到非9的内容时中断(返回false}

[9,9,9,9,9,9,9,9,9,9,9,9].all?{|x| x == 9} # => true
它是上述答案和我的一些答案的基准

        user       system      total        real
uniq    0.313000   0.000000   0.313000 (  0.312500)
delete  0.140000   0.000000   0.140000 (  0.140625)
count   0.079000   0.000000   0.079000 (  0.078125)
select  0.234000   0.000000   0.234000 (  0.234375)
detect  0.234000   0.000000   0.234000 (  0.234375)
all?    0.219000   0.000000   0.219000 (  0.218750)
如果
输入=[1]+[9]*9

        user     system      total        real
uniq    0.328000   0.000000   0.328000 (  0.328125)
delete  0.188000   0.000000   0.188000 (  0.203125)
count   0.187000   0.000000   0.187000 (  0.218750)
select  0.281000   0.016000   0.297000 (  0.296875)
detect  0.203000   0.000000   0.203000 (  0.203125)
all?    0.204000   0.000000   0.204000 (  0.203125)
如果
输入=[9]*9+[1]

        user     system      total        real
uniq    0.313000   0.000000   0.313000 (  0.328125)
delete  0.187000   0.000000   0.187000 (  0.187500)
count   0.172000   0.000000   0.172000 (  0.187500)
select  0.297000   0.000000   0.297000 (  0.312500)
detect  0.313000   0.000000   0.313000 (  0.312500)
all?    0.281000   0.000000   0.281000 (  0.281250)
如果
输入=[1,2,3,4,5,6,7,8,9]

        user     system      total        real
uniq    0.407000   0.000000   0.407000 (  0.406250)
delete  0.125000   0.000000   0.125000 (  0.125000)
count   0.125000   0.000000   0.125000 (  0.125000)
select  0.218000   0.000000   0.218000 (  0.234375)
detect  0.110000   0.000000   0.110000 (  0.109375)
all?    0.109000   0.000000   0.109000 (  0.109375)

编辑:查找完整的源代码。为@nash提供原始想法的道具


迭代并在找到元素!=匹配后立即返回false

def all_matches(arr, match)
  arr.each do |element|
    return false if element != match
  end
  true
end

对于从0到9的2M随机整数,50个循环(
n=50
):

用户系统总真实值 uniq 5.230000 0.010000 5.240000(5.219444) 计数2.680000 0.010000 2.690000(2.677923) 选择7.580000 0.060000 7.640000(7.634620) 检测0.0000000.0000000.000000(0.000068) 全部?0.0000000.0000000.000000(0.000046) 矿山0.0000000.0000000.000000(0.000032) 删除5.090000 0.020000 5.110000(5.101290) 任何?0.0000000.0000000.000000(0.000041) 用于生成数组的代码:

input = []
2000000.times { input << (rand*10).to_i }
input=[]

2000000次{input也许是最慢的,但这就是我想到的

input = [9,9,9,9,9,9,9,9,9,9,9,9]
!(input.any { |a| a != 9 })

下面是另一个更快的方法(上面的计数方法仍然是最快的):

还有一个稍微慢一点:

arr.inject(:&) == 9
以下是“水果”宝石的比较:

require 'fruity'
compare do
  count { arr.count(9) == arr.size }
  uniq { arr.uniq == [9] }  
  bitwise_and { arr.inject(:&) == 9 }  
  reject { arr.reject { |i| i==9 }.count == 0 }
end  


Running each test 8192 times. Test will take about 3 seconds.
count is faster than reject by 39.99999999999999% ± 10.0%
reject is faster than uniq by 10x ± 1.0
uniq is faster than bit_and by 30.000000000000004% ± 1.0%
这很有效:

> array = ['apple', 'banana']
> includes = array.uniq.include? 'banana'
> => true
此外,通过扩展,我们可以检查所有值是否相同,而不知道它们是什么:

> array = ['apple', 'banana', 'apple']
> all_same_values = (array.uniq.length > 1) ? false : true
> => false

这里有一个相关的答案:

,你的代码和我的代码,谢谢你提供了关于大括号的信息,我已经纠正了上面的例子。你的想象与实际的基准测试相比是微不足道的。谢谢,第一个是最快的(到目前为止:)),第二个是痛苦的缓慢。第一个是缓慢的,当你投入大量的投入。这里的其他解决方案会更快。你也能在元素都不同的情况下产生结果吗?在这种情况下,“全部”解决方案比“uniq”快。如果你给报告贴上标签,这将是一个非常好的答案(例如,
x.report“detect”do
),并针对未通过测试的阵列进行测试(例如,
[1]+[9]*9
[9]*9+[1]
)。对这些结果求平均值是个好主意,因此人们不需要梳理四个基准时间表。除此之外,非常好!要正确回答这个问题,需要知道实际数组有多大,以及非9值的概率有多大。对于一种类型的输入,速度更快的解决方案可能是slo对其他人来说是正确的。很好的一点,数组可以非常大,超过2M个元素,九的概率是1/10;)然后听起来你想要优化的是拒绝非9值,这是la@steenslag的解决方案。一个完整的数组扫描是昂贵的。@bashman:你真的希望2M个元素都是相同的,任何元素都有10%的概率有一个给定的值吗?:)看起来人们忽略了我的答案,因为它有0票,尽管给出了best性能。将此注释放在此处以邀请人们查看。当输入非常大且可能包含非9值时,请快速。请注意,
mine
基准测试结果是我的算法的结果。还请注意,如果将
如果arr.empty返回false?
添加到我的方法中(这可能是必需的,也可能不是必需的),它的性能仍然比不这样做的
all?
方法要好。我不明白为什么在上一个基准测试中计数速度如此之快。@steenslag:一定与此有关。还有另一个方法!:)请参阅我对比较基准测试的回答(我刚刚添加了您的方法,标记为
any?
)。
arr = [9,9,9,9,9,9,9,9,9,9,9,9]
arr.reject { |i| i==9 }.count == 0
arr.inject(:&) == 9
require 'fruity'
compare do
  count { arr.count(9) == arr.size }
  uniq { arr.uniq == [9] }  
  bitwise_and { arr.inject(:&) == 9 }  
  reject { arr.reject { |i| i==9 }.count == 0 }
end  


Running each test 8192 times. Test will take about 3 seconds.
count is faster than reject by 39.99999999999999% ± 10.0%
reject is faster than uniq by 10x ± 1.0
uniq is faster than bit_and by 30.000000000000004% ± 1.0%
> array = ['apple', 'banana']
> includes = array.uniq.include? 'banana'
> => true
> array = ['apple', 'banana', 'apple']
> all_same_values = (array.uniq.length > 1) ? false : true
> => false