
本文介绍一种基于 numpy 的向量化方法,用于从已排序、非重叠的区间序列中,精准提取所有“空区间”(即长度为 1 的区间)所构成的连续区域,并返回每个区域在原始区间数组中的起始与结束(左闭右开)索引。
本文介绍一种基于 numpy 的向量化方法,用于从已排序、非重叠的区间序列中,精准提取所有“空区间”(即长度为 1 的区间)所构成的连续区域,并返回每个区域在原始区间数组中的起始与结束(左闭右开)索引。
在处理分段标记、稀疏索引或区间合并等任务时,常需识别“空区间”——即满足 start == end - 1 的单位长度区间(如 [3,4)、[6,7))。更进一步,若多个空区间共享完全相同的 start 和 end 值(如示例中索引 1–3 均为 [3,4)),它们应被归为同一逻辑“区域”。目标是将这些连续且等值的空区间聚合成若干不相交的区域,并输出每个区域在原始区间数组中的起始下标(含)与结束下标(不含)。
以下为完整、可直接运行的解决方案:
import numpy as np
# 示例数据:已排序、非重叠、start ≤ end 的区间(end 为左开右闭)
interval_start_idxs = np.array([0, 3, 3, 3, 6, 7])
interval_end_excl_idxs = np.array([2, 4, 4, 4, 7, 9])
# 步骤 1:标记每个“空区间”
is_empty = (interval_start_idxs == interval_end_excl_idxs - 1)
# 步骤 2:识别区间值变化点 → 定义“区域边界”
# is_region_start[i] == True 表示第 i 个区间是某新区域的起点(含首项)
is_region_start = np.r_[True, np.diff(interval_start_idxs) != 0]
# is_region_end[i] == True 表示第 i 个区间是某区域的终点(即下一个区间开始新区域)
is_region_end = np.roll(is_region_start, -1)
# 步骤 3:仅保留既是区域边界、又是空区间的下标
empty_region_starts = np.nonzero(is_region_start & is_empty)[0]
empty_region_ends_excl = np.nonzero(is_region_end & is_empty)[0] + 1
print("空区间区域起始索引(含):", empty_region_starts.tolist()) # [1, 4]
print("空区间区域结束索引(不含):", empty_region_ends_excl.tolist()) # [4, 5]✅ 结果解读:
-
[1, 4)→ 对应原始区间索引1, 2, 3(三个[3,4)空区间组成一个连续区域); -
[4, 5)→ 对应原始区间索引4(单个[6,7)空区间独立成区)。
⚠️ 关键注意事项:
- 该方法严格依赖输入数组已按
interval_start_idxs(及隐含的interval_end_excl_idxs)升序排列,且区间互不重叠; -
np.roll(..., -1)巧妙利用了循环移位特性:末尾True被移至开头,恰好使原首项True成为末项is_region_end的标志,确保最后一个潜在区域的结束被正确捕获; - 若需兼容 Python 列表输出,可在最后调用
.tolist();如需进一步映射到实际坐标值(如[3,4)区域对应的物理范围),可结合interval_start_idxs[empty_region_starts]获取; - 时间复杂度为 O(n),全程无显式循环,充分发挥 NumPy 向量化优势,适用于百万级区间高效处理。
该模式可轻松扩展至多维区间分析或结合布尔掩码进行条件聚合,是构建高性能区间计算流水线的核心技巧之一。

















