如何在Python中从datetime列表查找指定数量的最近日期?
如何从datetime.date列表中找到与指定日期最接近的N个日期
看起来你需要从有序的日期列表里筛选出和目标日期最接近的N个日期,还要处理列表首尾的边界情况对吧?我这里有两个实用的解法,分别适用于不同场景:
方法一:通用解法(兼容有序/无序列表)
如果你的日期列表是无序的,或者不介意结果按差值排序,这个方法简单直接:给每个日期计算和目标日期的绝对差值,排序后取前N个即可。
import datetime def find_nearest(datelist, target_date, n=5): # 生成(差值绝对值, 原日期)的列表 date_with_diff = [(abs(date - target_date), date) for date in datelist] # 按差值从小到大排序 date_with_diff.sort() # 提取前n个日期返回 return [date for _, date in date_with_diff[:n]]
测试你的示例:
datelist = [datetime.date(2017, 3, 4), datetime.date(2017, 3, 6), datetime.date(2017, 3, 12), datetime.date(2017, 3, 27), datetime.date(2017, 3, 27), datetime.date(2017, 3, 29), datetime.date(2017, 3, 29), datetime.date(2017, 4, 2), datetime.date(2017, 4, 4)] my_date = datetime.date(2017, 4, 2) print(find_nearest(datelist, my_date, n=5))
输出会是按差值排序的结果:[datetime.date(2017, 4, 2), datetime.date(2017, 4, 4), datetime.date(2017, 3, 29), datetime.date(2017, 3, 29), datetime.date(2017, 3, 27)]
方法二:针对有序列表的高效解法(保持原时间顺序)
从你的示例来看,日期列表是按时间递增排序的,而且你希望结果也保持时间顺序,那这个方法更适合——用二分查找快速定位目标位置,再向两边扩展选取最近的元素,完美处理首尾边界:
import datetime import bisect def find_nearest_sorted(datelist, target_date, n=5): # 用二分查找找到目标日期的插入位置 insert_idx = bisect.bisect_left(datelist, target_date) left = insert_idx - 1 right = insert_idx result = [] # 向左右两边扩展,每次选差值更小的元素,直到凑够n个 while len(result) < n and (left >= 0 or right < len(datelist)): # 优先选左边的情况:左边存在,且要么右边越界,要么左边差值更小/相等 if left >= 0 and (right >= len(datelist) or abs(datelist[left] - target_date) <= abs(datelist[right] - target_date)): result.append(datelist[left]) left -= 1 else: result.append(datelist[right]) right += 1 # 因为是从中间向两边收集的,最后按时间排序恢复顺序 result.sort() return result
测试你的示例:
datelist = [datetime.date(2017, 3, 4), datetime.date(2017, 3, 6), datetime.date(2017, 3, 12), datetime.date(2017, 3, 27), datetime.date(2017, 3, 27), datetime.date(2017, 3, 29), datetime.date(2017, 3, 29), datetime.date(2017, 4, 2), datetime.date(2017, 4, 4)] my_date = datetime.date(2017, 4, 2) print(find_nearest_sorted(datelist, my_date, n=5))
输出完全符合你的期望:[datetime.date(2017, 3, 27), datetime.date(2017, 3, 29), datetime.date(2017, 3, 29), datetime.date(2017, 4, 2), datetime.date(2017, 4, 4)]
边界情况测试
这个方法能完美处理首尾场景:
# 目标日期早于所有日期,取前3个 my_date = datetime.date(2017, 2, 1) print(find_nearest_sorted(datelist, my_date, n=3)) # 输出: [datetime.date(2017, 3, 4), datetime.date(2017, 3, 6), datetime.date(2017, 3, 12)] # 目标日期晚于所有日期,取最后4个 my_date = datetime.date(2017, 5, 1) print(find_nearest_sorted(datelist, my_date, n=4)) # 输出: [datetime.date(2017, 3, 29), datetime.date(2017, 3, 29), datetime.date(2017, 4, 2), datetime.date(2017, 4, 4)]
选择建议
- 如果你的日期列表无序,或者不关心结果顺序:用方法一,实现简单;
- 如果列表是有序的,且需要结果保持时间顺序:用方法二,时间复杂度更低(O(log M + N),M是列表长度),效率更高。
内容的提问来源于stack exchange,提问作者tda
相关产品推荐
相关产品推荐

