如何提升时间片重叠检测循环的执行性能?
时间片重叠检测性能优化问题
我正在编写一个检测时间片是否重叠的脚本,现有处理函数intersection_checker如下:
def intersection_checker(foo, bar): if foo == bar: return True if foo[0] == bar[1] or foo[1] == bar[0]: return True if bar[0] < (foo[0] or foo[1]) < bar[1]: return True if foo[0] < (bar[0] or bar[1]) < foo[1]: return True return False
其中foo是包含两个datetime.time()对象的元组:
foo = (datetime.strptime('06:30:00','%H:%M:%S').time(), datetime.strptime('08:15:00','%H:%M:%S').time())
bar是包含200k+同类元组的集合。当前调用该函数的代码如下:
... if len(bar) > 1 and True in set(map(intersection_checker, repeat(foo), bar)): ...
代码可正常运行,但处理大数据量时性能极差。我尝试过用for循环遍历调用函数,但效果不如内置map。希望找到更高效的大数据处理方式,或优化重叠检测逻辑,且只需找到第一个返回True的情况即可,无需遍历全部bar元素。
优化方案
1. 修复并简化重叠检测逻辑
原函数中(foo[0] or foo[1])的写法存在逻辑错误,or会返回第一个为真的对象,而非用于区间判断的有效值。时间片重叠的核心判断逻辑可以简化为:两个区间不重叠的唯一情况是一个完全在另一个的左侧,取反即可得到重叠条件。同时增加对时间片起始/结束顺序的修正,避免传入顺序错误导致的误判。
优化后的函数:
def intersection_checker(foo, bar): # 确保时间片的起始<=结束 foo_start, foo_end = sorted(foo) bar_start, bar_end = sorted(bar) # 不重叠的情况取反,即为重叠 return not (foo_end <= bar_start or bar_end <= foo_start)
2. 高效遍历:短路求值终止迭代
原代码用set(map(...))会遍历所有元素并生成集合,完全浪费性能——我们只需要找到第一个匹配项就可以停止遍历。使用any()函数配合迭代器/生成器表达式,会在遇到第一个True时立即终止迭代,性能提升显著:
方式一:生成器表达式
if len(bar) > 1 and any(intersection_checker(foo, b) for b in bar): # 处理重叠逻辑 ...
方式二:map配合any()
from itertools import repeat if len(bar) > 1 and any(map(intersection_checker, repeat(foo), bar)): # 处理重叠逻辑 ...
3. 进阶优化:预排序+二分查找(针对复用场景)
如果bar集合固定不变,可以先对其按时间片起始时间排序,再用二分查找快速缩小需要检查的元素范围,进一步降低查询耗时:
import bisect # 预排序bar(仅需执行一次) sorted_bar = sorted(bar, key=lambda x: x[0]) def has_overlap(foo, sorted_intervals): foo_start, foo_end = sorted(foo) # 用二分查找定位第一个起始时间大于foo_end的区间 idx = bisect.bisect_right(sorted_intervals, (foo_end,), key=lambda x: x[0]) # 仅检查前idx个区间,后续区间不可能重叠 for interval in sorted_intervals[:idx]: bar_start, bar_end = sorted(interval) if not (foo_end <= bar_start or bar_end <= foo_start): return True return False # 调用 if len(sorted_bar) > 1 and has_overlap(foo, sorted_bar): # 处理重叠逻辑 ...
内容的提问来源于stack exchange,提问作者Raiksler
相关产品推荐
相关产品推荐

