获得两个日期之间的月份和年份的独特数组
我有两个Date
对象,例如:
first = Fri, 02 Dec 2016 last = Wed, 01 Mar 2017
获得它们之间数月和数年的独特数组的最有效方法是什么? 在这种情况下,我追求:
Dec 2016 Jan 2017 Feb 2017 Mar 2017
require 'date' def doit(first, last) (12*last.year + last.month - 12*first.year - first.month).times.map do first.strftime("%b %Y") first = first >> 1 end end first = Date.parse('Fri, 02 Dec 2016') last = Date.parse('Wed, 01 Mar 2017') doit(first, last) #=> ["Dec 2016", "Jan 2017", "Feb 2017", "Mar 2017"]
你可以创建一个日期数组,然后使用strftime
来设置正确的格式,并使用uniq
来避免重复的值,如下所示:
(first..last).map{ |date| date.strftime("%b %Y") }.uniq #=> ["Dec 2016", "Jan 2017", "Feb 2017", "Mar 2017"]
由于用户要求最有效的方式 (并且只是为了好玩),这里提出的解决方案的简单基准:
require 'benchmark' Benchmark.bmbm(10) do |bm| bm.report('Cary') do first = Date.new(1000, 1, 1) last = Date.new(2100, 1, 1) def doit(first, last) (12*last.year + last.month - 12*first.year - first.month).times.map do first.strftime("%b %Y") first = first >> 1 end end doit(first, last) end bm.report('Simple Lime') do first = Date.new(1000, 1, 1) last = Date.new(2100, 1, 1) dates = [] while first.beginning_of_month < last.end_of_month dates << first.strftime("%b %Y") first = first.next_month end end bm.report('Máté') do first = Date.new(1000, 1, 1) last = Date.new(2100, 1, 1) (first.beginning_of_month..last).map { |d| d.strftime("%b %Y") if d.day == 1 }.compact end bm.report('Gerry/Dan') do first = Date.new(1000, 1, 1) last = Date.new(2100, 1, 1) (first..last).map{ |date| date.strftime("%b %Y") }.uniq end end
结果:
Rehearsal ----------------------------------------------- Cary 0.020000 0.000000 0.020000 ( 0.025968) Simple Lime 0.190000 0.000000 0.190000 ( 0.192860) Máté 0.460000 0.020000 0.480000 ( 0.481839) Gerry/Dan 0.810000 0.020000 0.830000 ( 0.835931) -------------------------------------- total: 1.520000sec user system total real Cary 0.020000 0.000000 0.020000 ( 0.024871) Simple Lime 0.150000 0.000000 0.150000 ( 0.150696) Máté 0.390000 0.010000 0.400000 ( 0.398637) Gerry/Dan 0.710000 0.010000 0.720000 ( 0.711155)
不是一个漂亮的单行,但也没有单独走过每一天,所以对于大范围应该更快一点。
first = Date.new(2016, 12, 2) last = Date.new(2017, 3, 1) dates = [] while first.beginning_of_month < last.end_of_month dates << first.strftime("%b %Y") first = first.next_month end puts dates.inspect # => ["Dec 2016", "Jan 2017", "Feb 2017", "Mar 2017"]
假设这些变量:
first = Date.new(2016, 12, 2) last = Date.new(2017, 3, 1)
单线解决方案:
(first.beginning_of_month..last).map { |d| d.strftime("%b %Y") if d.day == 1 }.compact #=> ["Dec 2016", "Jan 2017", "Feb 2017", "Mar 2017"]
start_date=Date.new(2016,12,2) end_date=Date.new(2017,3,1) (start_date..end_date).map{ |d| d.strftime("%b %Y") }.uniq => ["Dec 2016", "Jan 2017", "Feb 2017", "Mar 2017"]