【问题标题】:Why Range#include? is much slower than greater or less than operator为什么是 Range#include?比大于或小于运算符慢得多
【发布时间】:2016-10-11 00:49:29
【问题描述】:

我有一个哈希数组,其中键是Date,值是Integer。 这是一个模拟它的测试代码。

hashes = 2000.times.map do |i|
  [Date.new(2017) - i.days, rand(100)]
end.to_h

我想获取特定时期的值。 一开始我是用Range#include?写的,但是很慢。

Benchmark.measure do
  hashes.select{|k,v| (Date.new(2012,3,3)..Date.new(2012,6,10)).include?(k)}
end

#<Benchmark::Tms:0x007fd16479bed0 @label="", @real=2.9242447479628026, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=2.920000000000016, @total=2.920000000000016>

使用简单的大于或小于运算符,速度提高了 60 倍。

Benchmark.measure do
  hashes.select{|k,v| k >= Date.new(2012,3,3) && k <= Date.new(2012,6,10)}
end

#<Benchmark::Tms:0x007fd162b61670 @label="", @real=0.05436371313408017, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.05000000000001137, @total=0.05000000000001137>

我认为这两个表达基本相同。

为什么差别这么大?

【问题讨论】:

    标签: ruby activesupport


    【解决方案1】:

    您需要使用Range#cover? 而不是Range#include?,并且只计算一次范围,而不是为measure 的每个元素计算一次。 cover? 将块变量 k 与范围的端点进行比较; include?(对于非数字对象,例如日期)将范围内的每个元素与块变量进行比较,直到找到匹配项或断定没有匹配项(类似于 Array#include?)。

    此外,您希望考虑hashes(散列)的每个元素的第一个也是唯一一个键,因此如果该散列是h,则第一个键值对是h.first,并且键那对是h.first.first

    require 'date'
    
    Benchmark.measure do
      r = Date.new(2012,3,3)..Date.new(2012,6,10)
      hashes.select{|h| r.cover? h.first.first }
    end
    

    就执行速度而言,这应该与您的第二种方法几乎相同。

    一个例子

    hashes = [{ Date.new(2012,3,1)=>1 }, { Date.new(2012,4,20)=>2 },
              { Date.new(2012,6,10)=>3 }, { Date.new(2012,6,11)=>4 }] 
      #=> [{#<Date: 2012-03-01 ((2455988j,0s,0n),+0s,2299161j)>=>1},
      #    {#<Date: 2012-04-20 ((2456038j,0s,0n),+0s,2299161j)>=>2},
      #    {#<Date: 2012-06-10 ((2456089j,0s,0n),+0s,2299161j)>=>3},
      #    {#<Date: 2012-06-11 ((2456090j,0s,0n),+0s,2299161j)>=>4}] 
    
    r = Date.new(2012,3,3)..Date.new(2012,6,10)
    hashes.select{|h| r.cover? h.first.first }
      #=> {#<Date: 2012-04-20 ((2456038j,0s,0n),+0s,2299161j)>=>2,
      #    #<Date: 2012-06-10 ((2456089j,0s,0n),+0s,2299161j)>=>3} 
    

    【讨论】:

      猜你喜欢
      • 2022-06-23
      • 1970-01-01
      • 1970-01-01
      • 2019-07-16
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多