Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 在任意时间范围内寻找最佳日/月/年间隔的算法?_Ruby_Algorithm - Fatal编程技术网

Ruby 在任意时间范围内寻找最佳日/月/年间隔的算法?

Ruby 在任意时间范围内寻找最佳日/月/年间隔的算法?,ruby,algorithm,Ruby,Algorithm,如果你有一个时间表,说: 2009年3月19日至2011年7月15日 是否有一种算法可以将该时间段分解为: March 19, 2009 - March 31, 2009 # complete days April 1, 2009 - December 31, 2009 # complete months January 1, 2010 - December 31, 2010 # complete years January 1, 2011 - June 30, 2011 #

如果你有一个时间表,说:

2009年3月19日至2011年7月15日

是否有一种算法可以将该时间段分解为:

March 19, 2009  - March 31, 2009    # complete days
April 1, 2009   - December 31, 2009 # complete months
January 1, 2010 - December 31, 2010 # complete years
January 1, 2011 - June 30, 2011     # complete months
July 1, 2011    - July 15, 2011     # complete days
更具体地说,给定任意时间段,甚至是第二个时间段,是否有一种算法可以将其划分为任意大小的最佳间隔数

因此,也许你不想把上面的日期范围划分为天/月/年,而是想把它划分为5天和18个月,类似这样的随机数据。这类算法有正式名称吗?一个ruby示例会很棒,但任何语言都可以

我已经能够拼凑出一些硬编码的Ruby东西来处理日/月/年示例:


…但似乎应该有一个算法来抽象它来处理任何时间间隔故障。也许这可以归结为简单的数学问题。

这可能是作弊,但通过使用active\u支持提供的日期函数,您可以大大简化代码。下面是我使用active_支持时产生的一些代码。算法非常简单。算出第一个月的最后一天,算出上个月的第一天。然后打印第一个月,将中间的月份分为几年,然后打印最后一个月。当然,这个简单的算法在很多方面都会因边缘情况而失效。下面的算法尝试优雅地处理这些边缘情况。我希望这会有帮助

require 'active_support/all'

# Set the start date and end date
start_date = Date.parse("March 19, 2009")
end_date = Date.parse("July 15, 2011")

if end_date < start_date
  # end date is before start date, we are done
elsif end_date == start_date
  # end date is the same as start date, print it and we are done
  print start_date.strftime("%B %e, %Y")
elsif start_date.year == end_date.year && start_date.month == end_date.month
  # start date and end date are in the same month, print the dates and we
  # are done
  print start_date.strftime("%B %e, %Y"), " - ",
    end_date.strftime("%B %e, %Y"), "\n"
else
  # start date and end date are in different months
  first_day_of_next_month = Date.new((start_date + 1.month).year,
    (start_date + 1.month).month, 1);
  first_day_of_end_month = Date.new(end_date.year, end_date.month, 1);

  # print out the dates of the first month
  if (first_day_of_next_month - 1.day) == start_date
    print start_date.strftime("%B %e, %Y"), "\n"
  else
    print start_date.strftime("%B %e, %Y"), " - ",
      (first_day_of_next_month - 1.day).strftime("%B %e, %Y"), "\n"
  end

  # now print the inbetween dates
  if first_day_of_next_month.year == (first_day_of_end_month - 1.day).year &&
    (first_day_of_end_month - 1.day) > first_day_of_next_month
    # start date and end date are in the same year, just print the inbetween
    # dates 
    print first_day_of_next_month.strftime("%B %e, %Y"), " - ",
      (first_day_of_end_month - 1.day).strftime("%B %e, %Y") + "\n"
  elsif first_day_of_next_month.year < (first_day_of_end_month - 1.day).year
    # start date and end date are in different years so we need to split across
    # years
    year_iter = first_day_of_next_month.year

    # print out the dates from the day after the first month to the end of the
    # year
    print first_day_of_next_month.strftime("%B %e, %Y"), " - ",
      Date.new(first_day_of_next_month.year, 12, 31).strftime("%B %e, %Y"),
      "\n"
    year_iter += 1

    # print out the full intermediate years
    while year_iter < end_date.year
      print Date.new(year_iter, 1, 1).strftime("%B %e, %Y"), " - ",
        Date.new(year_iter, 12, 31).strftime("%B %e, %Y"), "\n"
      year_iter += 1
    end

    # print from the begining of the last year until the last day before the the
    # end month
    print Date.new(first_day_of_end_month.year, 1, 1).strftime("%B %e, %Y"),
      " - ", (first_day_of_end_month - 1.day).strftime("%B %e, %Y"), "\n"
  end

  # finally print out the days of the last month
  if first_day_of_end_month == end_date
    print end_date.strftime("%B %e, %Y"), "\n"
  else
    print first_day_of_end_month.strftime("%B %e, %Y"), " - ",
      end_date.strftime("%B %e, %Y"), "\n"
  end
end
需要“主动支持/全部”
#设置开始日期和结束日期
start_date=date.parse(“2009年3月19日”)
end_date=date.parse(“2011年7月15日”)
如果结束日期<开始日期
#结束日期早于开始日期,我们已完成
elsif结束日期==开始日期
#结束日期和开始日期相同,打印出来,我们就完成了
打印开始日期strftime(“%B%e,%Y”)
elsif start\u date.year==end\u date.year&&start\u date.month==end\u date.month
#开始日期和结束日期在同一个月,打印日期,然后
#完成
打印开始日期.strftime(“%B%e,%Y”),“-”,
结束日期.strftime(“%B%e,%Y”),“\n”
其他的
#开始日期和结束日期在不同的月份
下个月的第一天=日期。新((开始日期+1.月)。年,
(开始日期+1个月)。月份,1);
月底的第一天=日期.new(月底日期.year,月底日期.month,1);
#打印出第一个月的日期
如果(下个月的第一天-1.天)=开始日期
打印开始日期.strftime(“%B%e,%Y”),“\n”
其他的
打印开始日期.strftime(“%B%e,%Y”),“-”,
(下个月的第一天-1天).strftime(“%B%e,%Y”),“\n”
结束
#现在打印中间日期
如果下个月的第一天。年==(下个月的第一天-1天)。年&&
(月末的第一天-1.天)>下月的第一天
#开始日期和结束日期在同一年,只需打印中间日期
#日期
打印下个月的第一天。strftime(“%B%e,%Y”),“-”,
(月底的第一天-1天).strftime(“%B%e,%Y”)+“\n”
elsif下个月的第一天年<(下个月的第一天-1天)。年
#开始日期和结束日期在不同的年份,因此我们需要在不同的年份进行拆分
#年头
年=下个月的第一天。年
#打印出从第一个月的第二天到月底的日期
#年
打印下个月的第一天。strftime(“%B%e,%Y”),“-”,
新日期(下个月的第一天,12,31)。标准时间(“%B%e,%Y”),
“\n”
年国际热核试验堆+=1
#打印完整的中间年份
而年份<结束日期.year
打印日期。新(1,1年)。标准时间(“%B%e,%Y”),“-”,
新日期(12,31年)。标准时间(“%B%e,%Y”),“\n”
年国际热核试验堆+=1
结束
#从去年年初开始打印,直到
#月末
打印日期.new(年月日的第一天,1,1).strftime(“%B%e,%Y”),
“-”,(月底的第一天-1天).strftime(“%B%e,%Y”),”\n”
结束
#最后打印出上个月的日期
如果月底第一天=月底日期
打印结束日期.strftime(“%B%e,%Y”),“\n”
其他的
打印月末的第一天。strftime(“%B%e,%Y”),“-”,
结束日期.strftime(“%B%e,%Y”),“\n”
结束
结束

从某种意义上讲,最初的问题非常简单,因为一年由月组成,一个月由天组成。因此,您可以只查看您的范围中有哪些部分是完整的年份,将它们去掉,然后迭代地查看下一个较小单元的完整实例的剩余部分

在任意情况下,这不一定是真的。在您的示例中,并非每18个月的间隔都可以划分为5天的间隔。这使事情变得复杂了很多,因为你不能再依赖这种单位层次结构了

任意情况的另一个复杂情况是,并非每个范围都有可行的细分。在您的示例中,2011年1月1日-2011年1月4日不能分解为5天18个月


因此,我建议您尝试制定一个更为约束的问题版本:)

一旦您将不同大小的月份加入到组合中,这会变得稍微复杂一些,但如果有一个好的日期库,同样的概念应该会起作用(并且可能会使“进步”更容易一些)

以psudocode开头的代码以python结尾-对此表示抱歉

intervals = [1, 60, 3600] # second minute hour
epoc = 0 # simple example case
start = 4 # 4 seconds past epoc
end = 7292 # 2:1:32

i = start
while i < end:
  for iidx, interval in enumerate(intervals):
    nIval = 0
    if(iidx+1 < len(intervals)):
      nIval = intervals[iidx+1]
    # wind down - find the next smallest interval that doesn't push us past END
    if (i-epoc) % interval == 0 and (i + nIval > end or not nIval):
      # move as close to end as possible
      pre = i
      while i+interval <= end:
        i += interval
      print "Stepped down %i to %i via %i" % (pre, i, interval)
    # wind up - find the next biggest interval boundary not past END
    elif nIval and (i-epoc) % nIval != 0:
      # advance to that interval boundry
      pre = i
      while (i-epoc) % nIval != 0 and i+interval <= end:
        i += interval
      print "Stepped up %i to %i via %i" % (pre, i, interval)
    if i == end:
      break
interval=[1,60,3600]#秒分小时
epoc=0#简单示例
启动时间=epoc后4秒
结束=7292#2:1:32
i=开始
当我结束时:
对于iidx,枚举中的间隔(间隔):
尼瓦尔=0
如果(iidx+1<长度(间隔)):
nIval=间隔[iidx+1]
#放松-找到下一个最小的间隔,它不会把我们推过终点
如果(i-epoc)%interval==0且(i+nIval>end或not nIval):
#尽可能靠近末端移动
pre=i
虽然i+interval yes,“optimal”可能不是正确的词。我想你只是在看