开发者

Get the month numbers for the current quarter

开发者 https://www.devze.com 2023-03-12 13:58 出处:网络
I need an array with the numbers for the months in the current quarter. I want to supp开发者_JS百科ly Date.today and then get eg. [1,2,3].

I need an array with the numbers for the months in the current quarter. I want to supp开发者_JS百科ly Date.today and then get eg. [1,2,3].

How do I do that in the easiest way? (Not by using switch/case).


def quarter(date)
  1 + ((date.month-1)/3).to_i
end


def quarter_month_numbers(date)
  quarters = [[1,2,3], [4,5,6], [7,8,9], [10,11,12]]
  quarters[(date.month - 1) / 3]
end


I would suggest building a hash indexed by month like so:

@quarters_by_month = Hash[(1..12).map {|v| i=((v-1)/3)*3; [v,[i+1, i+2, i+3]]}]

then any future lookup is just

@quarters_by_month[month]

Since @x3ro mentioned CPU time I thought it would be fun to benchmark all of the proposed solutions including the case statement which the OP wanted to exclude. Here are the results:

> ruby jeebus.rb 
                     user     system      total        real
case_statement:  0.470000   0.000000   0.470000 (  0.469372)
quarter_month:   0.420000   0.000000   0.420000 (  0.420217)
solution1:       0.740000   0.000000   0.740000 (  0.733669)
solution2:       1.630000   0.010000   1.640000 (  1.634004)
defined_hash:    0.470000   0.000000   0.470000 (  0.469814)

Here is the code:

def case_statement(month)
  case month
  when 1,2,3
    [1,2,3]
  when 4,5,6
    [4,5,6]
  when 7,8,9
    [7,8,9]
  when 10,11,12
    [10,11,12]
  else
    raise ArgumentError
  end
end

def defined_hash(month)
  @quarters_by_month[month]
end

def solution1(month)
  (((month - 1) / 3) * 3).instance_eval{|i| [i+1, i+2, i+3]}
end

def solution2(month)
  [*1..12][((month - 1) / 3) * 3, 3]
end

def quarter_month_numbers(month)
  @quarters[(month - 1) / 3]
end


require 'benchmark'

n = 1e6

Benchmark.bm(15) do |x|
  x.report('case_statement:') do
    for i in 1..n do
      case_statement(rand(11) + 1)
    end 
  end

  x.report('quarter_month:') do
    @quarters = [[1,2,3], [4,5,6], [7,8,9], [10,11,12]]

    for i in 1..n do
      quarter_month_numbers(rand(11) + 1)
    end 
  end

  x.report('solution1:') do
    for i in 1..n do
      solution1(rand(11) + 1)
    end 
  end

  x.report('solution2:') do
    for i in 1..n do
      solution2(rand(11) + 1)
    end 
  end

  x.report('defined_hash:') do
    @quarters_by_month = Hash[(1..12).map {|v| i=((v-1)/3)*3; [v,[i+1, i+2, i+3]]}]

    for i in 1..n do
      defined_hash(rand(11) + 1)
    end
  end
end


Solution 1

(((Date.today.month - 1) / 3) * 3).instance_eval{|i| [i+1, i+2, i+3]}

Solution 2

[*1..12][((Date.today.month - 1) / 3) * 3, 3]


You can do the following:

m = date.beginning_of_quarter.month
[m, m+1, m+2]

Demonstrated below in irb:

>> date=Date.parse "27-02-2011"
=> Sun, 27 Feb 2011  
>> m = date.beginning_of_quarter.month
=> 1
>> [m, m+1, m+2]
=> [1, 2, 3]

I don't know how fast this is compared to the other methods, perhaps @Wes can kindly benchmark this way as well.

One advantage of this approach I think is the clarity of the code. It's not convoluted.


Have a look at this little snippet:

months = (1..12).to_a
result = months.map do |m|
  quarter = (m.to_f / 3).ceil
  ((quarter-1)*3+1..quarter*3).to_a
end

puts result.inspect


For Array

month    = Date.today.month # 6
quarters = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
quarters.select { |quarter| quarter.include?(month) }
=> [[4, 5, 6]]

For Hash

month    = Date.today.month # 6
quarters = {
  [1, 2, 3]    => 'First  quarter',
  [4, 5, 6]    => 'Second quarter',
  [7, 8, 9]    => 'Third  quarter',
  [10, 11, 12] => 'Fourth quarter',
}
quarters.select { |quarter| quarter.include?(month) }
=> {[4, 5, 6]=>"Second quarter"}

Wish it helped ;)

0

精彩评论

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