NumPy中不转列表、不用循环查找子数组索引的方法
NumPy查找外层数组目标子数组索引的无循环实现
完全可以通过NumPy原生能力实现需求,不需要转换数组为列表,也不需要编写Python层面的for循环,所有运算均在NumPy底层C实现中完成,处理超大规模数据集时性能远高于转列表、Python循环的方案。
基础通用实现
代码逻辑和示例场景完全对齐,直接运行即可得到预期输出1:
import numpy as np arr = np.array([[11, 19, 18], [14, 15, 11], [19, 21, 46], [29, 21, 19]]) find_this_array = np.array([14, 15, 11]) # 生成逐行匹配的布尔掩码 match_mask = (arr == find_this_array).all(axis=1) # 取第一个匹配项的索引 target_index = np.where(match_mask)[0][0]
逻辑说明:
arr == find_this_array利用NumPy广播机制,逐元素对比每个子数组和目标数组的对应位置值,返回和原数组维度一致的布尔矩阵.all(axis=1)按行聚合判断,仅当某一行所有元素都和目标数组匹配时,对应位置返回True,得到一维匹配掩码np.where(match_mask)返回所有匹配位置的索引,取第一个值即和原生list.index行为一致的首次匹配位置
可以用np.flatnonzero简化为一行写法:
target_index = np.flatnonzero((arr == find_this_array).all(axis=1))[0]
超大规模数据集优化实现
如果数据集规模极大,可以将数组按行转换为内存视图,直接做整行内存块比对,省去逐元素判断的开销,性能比基础实现更高:
def find_subarray_idx(arr, target): # 按行长度定义单块内存的数据类型 row_dtype = np.dtype((np.void, arr.dtype.itemsize * arr.shape[1])) # 把二维数组转为一维的内存块视图,每个元素对应一整行 arr_row_view = arr.view(row_dtype).ravel() target_view = target.view(row_dtype) # 直接比对内存块,返回第一个匹配的索引 return np.flatnonzero(arr_row_view == target_view)[0] # 调用后直接返回结果1 target_index = find_subarray_idx(arr, find_this_array)
注意:上述两种实现如果遇到目标子数组不存在的情况,取
[0]时会触发索引越界错误,和原生list.index找不到元素抛出异常的行为对齐;如果需要容错,可以先通过match_mask.any()判断是否存在匹配项后再取值。
内容的提问来源于stack exchange,提问作者zay_117
相关产品推荐
相关产品推荐

