Get the month numbers for the current quarter
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 ;)
精彩评论