获得两个日期之间的月份和年份的独特数组

我有两个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"]