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”可能不是正确的词。我想你只是在看