1

我有下一本字典,我需要获取确定时期之间的缺失时期,换句话说,获取一个时期的结束日期和下一个时期的开始日期之间的时期。

{'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'}}

希望我解释正确和清楚。

提前致谢

4

4 回答 4

0

问题在于这一行:

for i in period:

字典没有排序,因此无法保证在您循环访问这些项目时将按什么顺序访问它们。您的其余代码假定它们将按顺序排列。尝试这个:

for i in sorted(period):

但请注意,如果您有更多元素对字符串进行排序,例如“8”、“9”、“10”、“11”,可能不会满足您的要求。

于 2019-04-24T09:26:14.637 回答
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'}}
于 2019-04-24T17:29:43.173 回答
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'}}

注意:您的间隔期由时期 i-1的 end_date 后一天和时期i的 start_date 前一天定义

于 2019-04-24T09:31:27.263 回答
-1

您没有告诉您使用的是哪个版本的 Python,但请注意字典中元素的顺序不会保留。如果您希望字典保持您应该使用的顺序collections.OrderedDicthttps ://docs.python.org/2/library/collections.html#collections.OrderedDict

于 2019-04-24T09:05:10.733 回答