使用纯Python或itertools按间隔规则对日期列表进行分组的方法
解决方案
itertools.groupby 本身无法直接满足你的需求,它的设计是基于单个元素的key值做连续分组,key函数只能接收当前元素作为输入,无法访问分组的起始元素、也不能保存上下文状态,自然不支持你需要的双日期比较逻辑。
推荐方案:手动遍历实现
这是最简洁、可读性最高、性能也最优的方案,时间复杂度为O(n),完全适配已排序的输入列表:
import datetime from typing import List def group_dates_by_interval(sorted_dates: List[datetime.date], max_days: int = 30) -> List[List[datetime.date]]: if not sorted_dates: return [] groups = [] current_group = [sorted_dates[0]] for date in sorted_dates[1:]: if (date - current_group[0]).days <= max_days: current_group.append(date) else: groups.append(current_group) current_group = [date] # 加入最后一个分组 groups.append(current_group) return groups
测试你的示例输入:
test_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) ] print(group_dates_by_interval(test_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)]]
可选方案:结合itertools实现
如果你一定要用itertools相关函数,可以用itertools.accumulate生成分组标记,再配合groupby做聚合,不过可读性会差一些:
import itertools import datetime test_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) ] # 生成每个日期对应的分组ID group_ids = itertools.accumulate( test_dates[1:], lambda group_id, curr_date: group_id if (curr_date - test_dates[group_id]).days <= 30 else group_id + 1, initial=0 ) # 按分组ID聚合后提取日期 result = [ [d for _, d in group] for _, group in itertools.groupby(zip(group_ids, test_dates), key=lambda x: x[0]) ]
内容的提问来源于stack exchange,提问作者lsgrep
相关产品推荐
相关产品推荐

