将日期时间列表拆分为日期。

11

我有一个排序好的日期时间列表:(带有日期间隔)

list_of_dts = [
              datetime.datetime(2012,1,1,0,0,0), 
              datetime.datetime(2012,1,1,1,0,0), 
              datetime.datetime(2012,1,2,0,0,0), 
              datetime.datetime(2012,1,3,0,0,0),
              datetime.datetime(2012,1,5,0,0,0),
              ]

我想将它们分成每天的列表:

result = [
          [datetime.datetime(2012,1,1,0,0,0), datetime.datetime(2012,1,1,1,0,0)],
          [datetime.datetime(2012,1,2,0,0,0)],
          [datetime.datetime(2012,1,3,0,0,0)],
          [], # Empty list for no datetimes on day
          [datetime.datetime(2012,1,5,0,0,0)]
         ]

从算法的角度来看,至少可以实现O(n)。

可能类似于以下内容: (显然这并不能处理错过的天数,并且会丢掉最后一个dt, 但它是一个开始)

def dt_to_d(list_of_dts):
    result = []
    start_dt = list_of_dts[0]
    day = [start_dt]
    for i, dt in enumerate(list_of_dts[1:]):
        previous = start_dt if i == 0 else list_of_dts[i-1]
        if dt.day > previous.day or dt.month > previous.month or dt.year > previous.year: 
            # split to new sub-list
            result.append(day)
            day = []
            # Loop for each day gap?
        day.append(dt)
    return result

有什么想法吗?


1
使用一个以datetime_value.date()作为键的字典列表。 - Paulo Scardine
4个回答

12

最简单的方法是使用dict.setdefault来将落在同一天的条目分组,然后循环遍历最低的日期到最高的日期:

>>> import datetime
>>> list_of_dts = [
              datetime.datetime(2012,1,1,0,0,0),
              datetime.datetime(2012,1,1,1,0,0),
              datetime.datetime(2012,1,2,0,0,0),
              datetime.datetime(2012,1,3,0,0,0),
              datetime.datetime(2012,1,5,0,0,0),
              ]

>>> days = {}
>>> for dt in list_of_dts:
        days.setdefault(dt.toordinal(), []).append(dt)

>>> [days.get(day, []) for day in range(min(days), max(days)+1)]
[[datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 1, 0)], 
 [datetime.datetime(2012, 1, 2, 0, 0)],
 [datetime.datetime(2012, 1, 3, 0, 0)],
 [],
 [datetime.datetime(2012, 1, 5, 0, 0)]]

另一种制作这样分组的方法是使用 itertools.groupby。 它专门为这种工作设计,但它没有提供一种填充丢失日期的空列表的方法:

>>> import itertools
>>> [list(group) for k, group in itertools.groupby(list_of_dts,
                                                   key=datetime.datetime.toordinal)]
[[datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 1, 0)], 
 [datetime.datetime(2012, 1, 2, 0, 0)],
 [datetime.datetime(2012, 1, 3, 0, 0)],
 [datetime.datetime(2012, 1, 5, 0, 0)]]

1
setdefault和toordinal是对我的答案的很好的改进。 :-) - Paulo Scardine
2
setdefault更简单的是defaultdict(来自于collections)。 - Amber
太好了,谢谢!我可以同时生成我的“days”列表和“list_of_dts”,这样效率会非常高。 - Alex L

7
您可以使用itertools.groupby轻松处理此类问题:
import datetime
import itertools

list_of_dts = [
        datetime.datetime(2012,1,1,0,0,0), 
        datetime.datetime(2012,1,1,1,0,0), 
        datetime.datetime(2012,1,2,0,0,0), 
        datetime.datetime(2012,1,3,0,0,0),
        datetime.datetime(2012,1,5,0,0,0),
        ]

print [list(g) for k, g in itertools.groupby(list_of_dts, key=lambda d: d.date())]

好知道 - 谢谢!但它不能处理缺少日期的空列表要求。 - Alex L

1

填补空缺:

date_dict = {}
for date_value in list_of_dates:
    if date_dict.has_key(date_value.date()):
        date_dict[date_value.date()].append(date_value)
    else:
        date_dict[date_value.date()] = [ date_value ]
sorted_dates = sorted(date_dict.keys())
date = sorted_dates[0]
while date <= sorted_dates[-1]:
    print date_dict.get(date, [])
    date += datetime.timedelta(1)

结果:

[datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 1, 0)]
[datetime.datetime(2012, 1, 2, 0, 0)]
[datetime.datetime(2012, 1, 3, 0, 0)]
[]
[datetime.datetime(2012, 1, 5, 0, 0)]

这个解决方案不需要对原始日期时间列表进行排序。


1
list_of_dts = [
            datetime.datetime(2012,1,1,0,0,0), 
            datetime.datetime(2012,1,1,1,0,0), 
            datetime.datetime(2012,1,2,0,0,0), 
            datetime.datetime(2012,1,3,0,0,0),
            datetime.datetime(2012,1,5,0,0,0),
            ]

groupedByDay={}
for date in list_of_dts:
    if date.date() in groupedByDay:
        groupedByDay[date.date()].append(date)
    else:
        groupedByDay[date.date()]=[date]

现在你有一个字典,其中日期是键,值是类似日期的列表。

如果你坚持要一个列表

result = groupedByDay.values()
result.sort()

现在的结果是一个列表,其中所有相同日期的日期都被分组在一起。


2
date.date() in groupedByDay.keys() 的时间复杂度为 O(n)。你能否将其替换为 date.date() in groupedByDay?这样时间复杂度就变成了 O(1)。 - reclosedev
做完了。谢谢你的提示。我最近刚学Python..每天都学到新东西。 - Lex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接