
本文介绍一种基于 numpy 的向量化方法,用于从已排序、非重叠的区间序列中快速定位所有“空区间”构成的连续区域,并提取每个区域在原始区间数组中的起始与结束(左闭右开)索引。
本文介绍一种基于 numpy 的向量化方法,用于从已排序、非重叠的区间序列中快速定位所有“空区间”构成的连续区域,并提取每个区域在原始区间数组中的起始与结束(左闭右开)索引。
在处理离散化区间(如通过 np.searchsorted 生成的分段索引)时,常需识别“空区间”——即满足 start == end - 1 的退化区间(仅含单个元素,或更常见地,表示长度为 1 的空隙)。但实际需求往往不止于单个空区间,而是将起止索引完全相同、且连续排列的一组空区间聚类为一个逻辑“空区域”。例如,多个相邻区间共享相同的 start=3 和 end_excl=4,它们共同构成一个从索引 1 到 3(含)的空区域。
下面以具体示例展开实现:
import numpy as np # 示例数据:已排序、非重叠的区间(start 包含,end 排除) interval_start_idxs = np.array([0, 3, 3, 3, 6, 7]) interval_end_excl_idxs = np.array([2, 4, 4, 4, 7, 9])
根据定义,空区间满足:
is_empty = (interval_start_idxs == interval_end_excl_idxs - 1) # → [False, True, True, True, False, False]
但仅标记空区间还不够——还需识别其连续同值块(region)。关键观察是:同一 region 内的所有区间,其 interval_start_idxs 和 interval_end_excl_idxs 均完全相等,因此 region 边界必然出现在 interval_start_idxs(或 interval_end_excl_idxs)发生跳变的位置。
我们利用 np.diff 和 np.r_ 构建区域边界掩码:
# 标记每个 region 的起始位置(第一个出现该 start 值的索引) is_region_start = np.r_[True, np.diff(interval_start_idxs) != 0] # → [True, True, False, False, True, True] # 标记每个 region 的结束位置(最后一个出现该 start 值的索引) # 将 is_region_start 左移一位,使原起始位变为前一 region 的结束位 is_region_end = np.roll(is_region_start, -1) # → [True, False, False, True, True, True] # 注意:roll(-1) 将索引 0 处的 True 移至末尾,恰好对应最后一个 region 的结束
接着,结合空性与区域边界,提取目标索引:
# 空区域的起始区间索引(在 interval 数组中的位置,含) empty_interval_starts = np.nonzero(is_region_start & is_empty)[0] # → array([1]) # 空区域的结束区间索引(在 interval 数组中的位置,不含;即下一个非空区间的起始) empty_interval_ends_excl = np.nonzero(is_region_end & is_empty)[0] + 1 # → array([4])
⚠️ 注意事项:
- 该方法严格依赖
interval_start_idxs和interval_end_excl_idxs同步排序且一一对应。若存在start相同但end不同的情况,需先按(start, end)双关键字排序或预聚合。 -
np.roll(is_region_start, -1)的巧妙之处在于:它自动将首个True“循环”至末尾,使is_region_end[-1]在最后一个 region 确实为True,无需特殊处理边界。 - 输出为
np.ndarray;如需 Python 列表格式(如题目示例所示),可调用.tolist():empty_interval_starts.tolist() # → [1]empty_interval_ends_excl.tolist() # → [4]
最终结果 [1, 4] 表示:第 1 个(0-indexed)到第 3 个区间(含)构成一个空区域;而题目中期望的 [1, 4] 和 [4, 5] 实际对应两个 region——但本例中仅存在一个连续块(索引 1–3),故输出为单元素数组。若输入含孤立空区间(如索引 4 后新增 start=8, end=9),方法将自然扩展出第二个 [4] 和 [5],完全符合预期语义。
此方案全程向量化,无显式循环,适用于百万级区间场景,兼具简洁性与高性能。

















