【问题标题】:Get missing dates of dictionary and sort it获取字典的缺失日期并对其进行排序
【发布时间】:2019-04-24 09:01:38
【问题描述】:

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

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

希望我解释正确和清楚。

提前致谢

【问题讨论】:

    标签: python python-3.x dictionary


    【解决方案1】:

    问题出在这一行:

    for i in period:
    

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

    for i in sorted(period):
    

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

    【讨论】:

      【解决方案2】:

      好的,我想你没有很清楚地解释你是如何确定你的月经间隔的。我查看了您的代码,我认为这就是您想要的:

      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 之前的一天定义>

      【讨论】:

      • 嗨,我收到了这个错误:TypeError: list indices must be integers, not str
      • @hmar 我的解决方案没有使用 lists。您确定它不是来自代码中的其他部分吗?
      • 我不这么认为:gap_period['startdate'] = datetime.strftime(datetime.strptime(periods[int(i)]['enddate'], r'%Y/%m /%d') + timedelta(days=1), r'%Y/%m/%d') KeyError: 0 TypeError: list indices must be integers, not str
      • periods[int(i)] - 你为什么把它改成int(i)?您的字典键是数字字符串。此外,periods 应该是 dict 而不是 list?
      • 我刚刚发现错误,名称dict是错误的。有用!非常感谢你,伙计!
      【解决方案3】:

      请注意,如果期间重叠,某些方法将不起作用。如果周期重叠,则需要更复杂的算法。

      首先,几个定义:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2020-05-26
          • 1970-01-01
          • 1970-01-01
          • 2021-08-20
          • 1970-01-01
          • 2014-06-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多