纯 python 或 itertools 按每个日期之间的天数差异对日期列表进行分组

Pure python or itertools group a list of dates by days difference between each date

有一个日期列表:

[
datetime.date(2006, 8, 15),
datetime.date(2006, 9, 12),
datetime.date(2007, 8, 10),
datetime.date(2021, 4, 6),
datetime.date(2021, 4, 16),
datetime.date(2021, 4, 19)
...
]

我想要包含所有日期之间最多相隔 30 天的日期的组(组的第一个元素与这些组的最后一个元素之间的距离将 <= 30 天)

例如,使用前面的列表,我将得到:

我尝试使用 iter-tools groupby,但关键函数不允许像 "lambda x,y: (x-y).days <= 30 这样的 2 个日期比较。 ...”我不知道我是否可以使用 groupby 来解决这个问题,或者我需要其他 itertools 功能。 我知道我可以为它构建一个 python 算法,但我认为将存在一个简单的选项来解决这个问题,但我没有找到它:(

谢谢!

在这种情况下,使用普通旧 for 循环的迭代解决方案非常简单。

我认为使用 itertools 来解决这个问题不会容易或有效,因为在这种情况下分组取决于数据的上下文,这可能会产生 O(N^ 2) 解决方案,而迭代方法是 O(N)。

dts = [
datetime.date(2006, 8, 15),
datetime.date(2006, 9, 12),
datetime.date(2007, 8, 10),
datetime.date(2021, 4, 6),
datetime.date(2021, 4, 16),
datetime.date(2021, 4, 19)
]

def groupDateTimes(dts):
    i = 0
    ans = []
    group = []
    delta30days = datetime.timedelta(days=30)
    while i < len(dts):
        cur = dts[i]
        if not group:
            group.append(cur)
        elif cur - group[0] <= delta30days:
            group.append(cur)
        else:
            ans.append(group)
            group = [cur]
        i += 1
    if group:
        ans.append(group)
    return ans

print(groupDateTimes(dts)) // [[datetime.date(2006, 8, 15), datetime.date(2006, 9, 12)], [datetime.date(2007, 8, 10)], [datetime.date(2021, 4, 6), datetime.date(2021, 4, 16), datetime.date(2021, 4, 19)]]

这里有一个 pandas 解决方案,将日期与下一个日期进行比较,并检查两者之间是否有 30 天。然后它分配一个组号 cumsum:

import pandas as pd
import datetime

data = [ datetime.date(2006, 8, 15), datetime.date(2006, 9, 12), datetime.date(2007, 8, 10), datetime.date(2021, 4, 6), datetime.date(2021, 4, 16), datetime.date(2021, 4, 19)]

df = pd.DataFrame(data, columns=['date'])
df['groups'] = (df['date'].diff() > pd.Timedelta(30, unit='D')).cumsum()

输出:

date groups
0 2006-08-15 0
1 2006-09-12 0
2 2007-08-10 1
3 2021-04-06 2
4 2021-04-16 2
5 2021-04-19 2

或者如果您只想将列表列表作为输出:df.groupby((df['date'].diff() > pd.Timedelta(30, unit='D')).cumsum()).agg(list)['date'].to_list()

itertools.groupby 用于对彼此不依赖的项目进行分组。在您的情况下,当当前日期比当前组的第一个日期晚 30 天以上时,通过插入一个新组来简单地遍历日期列表以构建组列表既容易又清晰:

dates = [
    datetime.date(2006, 8, 15),
    datetime.date(2006, 9, 12),
    datetime.date(2007, 8, 10),
    datetime.date(2021, 4, 6),
    datetime.date(2021, 4, 16),
    datetime.date(2021, 4, 19),
    datetime.date(2021, 5, 7)
]
threshold = datetime.timedelta(30)
groups = []
for date in dates:
    if not groups or date - group[0] > threshold:
        group = []
        groups.append(group)
    group.append(date)

groups 会变成:

[[datetime.date(2006, 8, 15), datetime.date(2006, 9, 12)],
 [datetime.date(2007, 8, 10)],
 [datetime.date(2021, 4, 6), datetime.date(2021, 4, 16), datetime.date(2021, 4, 19)],
 [datetime.date(2021, 5, 7)]]