如何高效检查列表中的时间戳是否存在于两个时间戳之间?
优化方案:用bisect库高效实现时间区间查询
核心思路
bisect库专门用于有序序列的快速查找,而datetime对象本身支持比较运算,所以我们只需要把字符串时间转成datetime对象并排序,就能借助bisect快速定位区间边界,彻底避免低效的全量遍历。
具体实现步骤
- 一次性转换时间格式并排序
把所有字符串时间转成datetime实例,再对列表排序——这两步只需要执行一次(在循环查询前完成),后续查询直接复用处理好的有序列表。 - 用bisect定位区间边界
每次查询时,把起止时间也转成datetime,用bisect_left和bisect_right找到它们在有序列表中的插入位置,通过判断两个位置是否不等,就能快速知道区间内是否存在匹配的时间戳。
完整代码示例
from datetime import datetime import bisect # 原始时间字符串列表 insulin_timestamps = ['2017/07/01 13:23:42', '2017/11/01 00:56:40', '2018/02/18 22:01:09'] # 预处理:转换为datetime并排序(仅执行一次) time_format = "%Y/%m/%d %H:%M:%S" sorted_dts = sorted(datetime.strptime(ts, time_format) for ts in insulin_timestamps) # 可循环调用的查询函数 def has_timestamp_in_range(start_str, end_str): start_dt = datetime.strptime(start_str, time_format) end_dt = datetime.strptime(end_str, time_format) # 找到第一个>=start_dt的元素索引 left_pos = bisect.bisect_left(sorted_dts, start_dt) # 找到第一个>end_dt的元素索引 right_pos = bisect.bisect_right(sorted_dts, end_dt) # 左右位置不等,说明区间内存在匹配元素 return left_pos != right_pos # 测试示例 start_time = '2017/10/31 22:00:11' end_time = '2017/11/01 01:59:40' print(has_timestamp_in_range(start_time, end_time)) # 输出True
效率说明
- 预处理(转换+排序)的时间复杂度是O(n log n),仅执行一次。
- 每次查询的时间复杂度是O(log n),相比嵌套循环的O(n),在数据量大、查询次数多的场景下效率提升极其明显。
额外优化选项
如果追求极致性能,可以把datetime转成整数时间戳(dt.timestamp()),用整数列表做bisect,原理完全一致:
# 预处理:转成时间戳整数并排序 sorted_ts = sorted(dt.timestamp() for dt in sorted_dts) def has_timestamp_in_range_v2(start_str, end_str): start_ts = datetime.strptime(start_str, time_format).timestamp() end_ts = datetime.strptime(end_str, time_format).timestamp() left_pos = bisect.bisect_left(sorted_ts, start_ts) right_pos = bisect.bisect_right(sorted_ts, end_ts) return left_pos != right_pos
内容的提问来源于stack exchange,提问作者Tianna Wrona
相关产品推荐
相关产品推荐

