如何在Ruby中的两个日期之间获得所有星期日?

我正在处理用户输入日期范围的表单,并从一周中的一天/几天的复选框列表中选择,即周日,周一,周二,周三,周四,周五和周六。

提交表单后,我需要一种方法来获取根据所选日期输入的两个日期之间的日期列表,即所给出的两个日期之间的所有星期一和星期四。 我查看了文档,但无法确定如何有效地执行此操作,即ruby方式。

有趣的一个! :d

start_date = Date.today # your start end_date = Date.today + 1.year # your end my_days = [1,2,3] # day of the week in 0-6. Sunday is day-of-week 0; Saturday is day-of-week 6. result = (start_date..end_date).to_a.select {|k| my_days.include?(k.wday)} 

使用上面的数据,您将获得从现在到明年之间所有周一/周二/周二的数组。

另一种方法是按日期对日期范围进行wday然后选择一周中的某一天:

 datesByWeekday = (start_date..end_date).group_by(&:wday) datesByWeekday[6] # All Sundays 

例如,要在2016年3月获得所有星期日:

 > (Date.new(2016,03,01)..Date.new(2016,04,01)).group_by(&:wday)[6] => [Sat, 05 Mar 2016, Sat, 12 Mar 2016, Sat, 19 Mar 2016, Sat, 26 Mar 2016] 

对速度感到好奇,所以这就是我所做的。

以下是解决问题的两种方法:

  • 使用范围和filter
  • 找到第一天并添加1.week一天直到停止

对于远程解决方案,有不同的方法可以使用该范围:

  • 记下所有日期并按工作日分组
  • 运行范围上的选择function
  • 将范围转换为数组,然后运行select

如何选择日期也很重要:

  • 运行include? 在要求的日子里
  • 找到两个数组之间的交集并检查是否为空

我做了一个文件来测试所有这些方法。 我叫它test.rb 我把它放在rails应用程序的根目录下。 我通过输入以下命令来运行它:

  • rails c
  • load 'test.rb'

这是测试文件:

 @days = { 'Sunday' => 0, 'Monday' => 1, 'Tuesday' => 2, 'Wednesday' => 3, 'Thursday' => 4, 'Friday' => 5, 'Saturday' => 6, } @start = Date.today @stop = Date.today + 1.year # use simple arithmetic to count number of weeks and then get all days by adding a week def division(args) my_days = args.map { |key| @days[key] } total_days = (@stop - @start).to_i start_day = @start.wday my_days.map do |wday| total_weeks = total_days / 7 remaining_days = total_days % 7 total_weeks += 1 if is_there_wday? wday, remaining_days, @stop days_to_add = wday - start_day days_to_add = days_to_add + 7 if days_to_add.negative? next_day = @start + days_to_add days = [] days << next_day (total_weeks - 1).times do next_day = next_day + 1.week days << next_day end days end.flatten.sort end def is_there_wday?(wday, remaining_days, stop) new_start = stop - remaining_days (new_start..stop).map(&:wday).include? wday end # take all the dates and group them by weekday def group_by(args) my_days = args.map { |key| @days[key] } grouped = (@start..@stop).group_by(&:wday) my_days.map { |wday| grouped[wday] }.flatten.sort end # run the select function on the range def select_include(args) my_days = args.map { |key| @days[key] } (@start..@stop).select { |x| my_days.include? x.wday } end # run the select function on the range def select_intersect(args) my_days = args.map { |key| @days[key] } (@start..@stop).select { |x| (my_days & [x.wday]).any? } end # take all the dates, convert to array, and then select def to_a_include(args) my_days = args.map { |key| @days[key] } (@start..@stop).to_a.select { |k| my_days.include? k.wday } end # take all dates, convert to array, and check if interection is empty def to_a_intersect(args) my_days = args.map { |key| @days[key] } (@start..@stop).to_a.select { |k| (my_days & [k.wday]).any? } end many = 10_000 Benchmark.bmbm do |b| [[], ['Sunday'], ['Sunday', 'Saturday'], ['Sunday', 'Wednesday', 'Saturday']].each do |days| str = days.map { |x| @days[x] } b.report("#{str} division") { many.times { division days }} b.report("#{str} group_by") { many.times { group_by days }} b.report("#{str} select_include") { many.times { select_include days }} b.report("#{str} select_&") { many.times { select_intersect days }} b.report("#{str} to_a_include") { many.times { to_a_include days }} b.report("#{str} to_a_&") { many.times { to_a_intersect days }} end end 

排序结果

 [] division 0.017671 [] select_include 2.459335 [] group_by 2.743273 [] to_a_include 2.880896 [] to_a_& 4.723146 [] select_& 5.235843 [0] to_a_include 2.539350 [0] select_include 2.543794 [0] group_by 2.953319 [0] division 4.494644 [0] to_a_& 4.670691 [0] select_& 4.897872 [0, 6] to_a_include 2.549803 [0, 6] select_include 2.553911 [0, 6] group_by 4.085657 [0, 6] to_a_& 4.776068 [0, 6] select_& 5.016739 [0, 6] division 10.203996 [0, 3, 6] select_include 2.615217 [0, 3, 6] to_a_include 2.618676 [0, 3, 6] group_by 4.605810 [0, 3, 6] to_a_& 5.032614 [0, 3, 6] select_& 5.169711 [0, 3, 6] division 14.679557 

趋势

  • range.selectrange.to_a.select略快
  • include?intersect.any?更快intersect.any?
  • group_byintersect.any?更快intersect.any? 但比include?include?
  • 当没有给出任何东西时, division很快,但是通过的越多的params显着减慢

结论

如果你把selectinclude?结合起来include? ,您有最快,最可靠的解决方案