我有下一本字典,我需要获取确定期间之间的缺失期,换句话说,获取一个期间的结束日期与下一个开始日期之间的期间。
{'0': {'enddate': u'2015/08/31',
'startdate': u'2015/01/01'},
'1': {'enddate': u'2018/10/31',
'startdate': u'2017/01/01'},
'2': {'enddate': u'2019/03/29',
'startdate': u'2019/01/01'}}
The function who get this data is the next:
def periods(periods):
total_periods={}
for period in periods:
total_periods[period] = {}
for startdate in periods[period][0]:
total_periods[period]['startdate'] = startdate
for enddate in periods[period][-1]:
total_periods[period]['enddate'] = enddate
I have the next code that get the missing periods but i cant to order whith my expect results.
gaps={}
s=[]
e=[]
for i in period:
s.append(datetime.strftime(datetime.strptime(period[i]['enddate'],'%Y/%m/%d')+timedelta(days=1),'%Y/%m/%d'))
e.append(datetime.strftime(datetime.strptime(period[i]['startdate'],'%Y/%m/%d')+timedelta(days=-1),'%Y/%m/%d'))
for i in range(len(s)):
if i==len(s)-1:
break
d={}
d['startdate']=s[i]
d['enddate']=e[i+1]
gaps[str(i)]=d
The output of these code is the next:
{'0': {'enddate': '2014/12/31', 'startdate': '2018/11/01'},
'1': {'enddate': '2018/12/31', 'startdate': '2015/09/01'}}
但是错了,因为我需要下一个结果:
{'0': {'enddate': '2016/12/31', 'startdate': '2015/09/01'},
'1': {'enddate': '2018/12/31', 'startdate': '2018/11/01'}}
希望我能正确解释并清除问题。
预先感谢
答案 0 :(得分:0)
问题出在这一行:
for i in period:
字典不排序,因此不能保证在将它们循环时将按什么顺序访问这些项。您的其余代码假定它们将按顺序排列。试试这个:
for i in sorted(period):
但是请注意,如果您有更多元素对字符串进行排序,例如'8','9','10','11',则可能无法满足您的要求。
答案 1 :(得分:0)
好的,我想您没有很清楚地解释如何确定月经间隔。我查看了您的代码,我认为这就是您想要的:
from datetime import datetime, timedelta
periods = {'0': {'enddate': u'2015/08/31', 'startdate': u'2015/01/01'},
'1': {'enddate': u'2018/10/31', 'startdate': u'2017/01/01'},
'2': {'enddate': u'2019/03/29', 'startdate': u'2019/01/01'}}
gaps = {}
for i in range(len(periods) - 1):
gap_period = {}
gap_period['startdate'] = datetime.strftime(datetime.strptime(periods[str(i)]['enddate'], r'%Y/%m/%d') + timedelta(days=1), r'%Y/%m/%d')
gap_period['enddate'] = datetime.strftime(datetime.strptime(periods[str(i+1)]['startdate'], r'%Y/%m/%d') + timedelta(days=-1), r'%Y/%m/%d')
gaps[str(i)] = gap_period
>>>gaps
{'0': {'startdate': '2015/09/01', 'enddate': '2016/12/31'}, '1': {'startdate': '2018/11/01', 'enddate': '2018/12/31'}}
注意:您的空缺期由 Period i-1 的结束日期之后的一天和 Period i 的开始日期之前的一天定义>
答案 2 :(得分:0)
请注意,如果句点重叠,则某些方法将不起作用。如果周期重叠,则需要更复杂的算法。
首先,一些定义:
>>> from datetime import datetime, timedelta
>>> dates_by_num = {'0': {'enddate': '2015/08/31', 'startdate':'2015/01/01'}, '1': {'enddate': '2018/10/31', 'startdate': '2017/01/01'}, '2': {'enddate': '2019/03/29', 'startdate': '2019/01/01'}}
>>> def to_date(s): return datetime.strptime(s, r'%Y/%m/%d')
>>> def to_string(d): return datetime.strftime(d, r'%Y/%m/%d')
关键思想是对所有日期进行排序,并保留一个值来指示它是开始(1
)还是结束(-1
)日期。
>>> dates = sorted(d_s for _, v in dates_by_num.items() for d_s in ((to_date(v['startdate']), 1), (to_date(v['enddate']), -1)))
>>> dates
[(datetime.datetime(2015, 1, 1, 0, 0), 1), (datetime.datetime(2015, 8, 31, 0, 0), -1), (datetime.datetime(2017, 1, 1, 0, 0), 1), (datetime.datetime(2018, 10, 31, 0, 0), -1), (datetime.datetime(2019, 1, 1, 0, 0), 1), (datetime.datetime(2019, 3, 29, 0, 0), -1)]
现在,我们遍历日期并保持c
的间隔数:每个开始日期,c
增加,每个结束日期,c
减少,因此c
是开始日期数减去结束日期数。当(且仅当)c == 0
时,我们没有时间了。
>>> gaps = []
>>> last_c, last_d = 1, 0
>>> c = 0
>>> for d, s in dates:
... c += s
... assert c >= 0 # c is the number of intervals we are in
... if last_c == 0 and d - last_d > timedelta(days=1): # we were out of all the intervals
... gaps.append({'startdate': to_string(last_d+timedelta(days=1)), 'endate': to_string(d+timedelta(days=-1))})
... last_c, last_d = c, d
...
我添加了一个测试以消除空隙(d - last_d > timedelta(days=1)
)。要获得您想要的演示文稿:
>>> {str(i): d for i, d in enumerate(gaps)}
{'0': {'startdate': '2015/09/01', 'endate': '2016/12/31'}, '1': {'startdate': '2018/11/01', 'endate': '2018/12/31'}}
代码:
from datetime import datetime, timedelta
def to_date(s): return datetime.strptime(s, r'%Y/%m/%d')
def to_string(d): return datetime.strftime(d, r'%Y/%m/%d')
def find_gaps(dates_by_num):
dates = sorted(d_s for _, v in dates_by_num.items() for d_s in ((to_date(v['startdate']), 1), (to_date(v['enddate']), -1)))
gaps = []
last_c, last_d = 1, 0
c = 0
for d, s in dates:
c += s
assert c >= 0 # c is the number of interval we are in
if last_c == 0 and d - last_d > timedelta(days=1): # we were not in any interval
gaps.append({'startdate': to_string(last_d+timedelta(days=1)), 'endate': to_string(d+timedelta(days=-1))})
last_c, last_d = c, d
return {str(i): d for i, d in enumerate(gaps)}
示例:
>>> find_gaps({'0': {'enddate': '2018/08/31', 'startdate':'2015/01/01'}, '1': {'enddate': '2018/10/31', 'startdate': '2017/01/01'}, '2': {'enddate': '2019/03/29', 'startdate': '2019/01/01'}})
{'0': {'startdate': '2018/11/01', 'endate': '2018/12/31'}}
>>> find_gaps({'0': {'enddate': '2016/12/31', 'startdate':'2015/01/01'}, '1': {'enddate': '2018/10/31', 'startdate': '2017/01/01'}, '2': {'enddate': '2019/03/29', 'startdate': '2019/01/01'}})
{'0': {'startdate': '2018/11/01', 'endate': '2018/12/31'}}
>>> find_gaps({'0': {'enddate': '2016/08/31', 'startdate':'2015/01/01'}, '1': {'enddate': '2019/10/31', 'startdate': '2017/01/01'}, '2': {'enddate': '2019/03/29', 'startdate': '2019/01/01'}})
{'0': {'startdate': '2016/09/01', 'endate': '2016/12/31'}}
答案 3 :(得分:-1)
您没有告诉您正在使用哪个版本的Python,但是请注意,字典中的元素顺序不会保留。如果希望字典保持顺序,则应使用collections.OrderedDict
代替:https://docs.python.org/2/library/collections.html#collections.OrderedDict