您基本上是在寻找另一个列表中的列表的起始索引。
方法 #1: 解决此问题的一种方法是创建滑动窗口,其中包含我们要搜索的列表中的元素,从而给我们一个 2D
数组,然后只需使用 NumPy 广播
对先前获得的 2D
滑动窗口版本的每一行与搜索列表进行广播比较即可。 因此,一种方法是 -
def strided_app(a, L, S ):
nrows = ((a.size-L)//S)+1
n = a.strides[0]
return np.lib.stride_tricks.as_strided(a, shape=(nrows,L), strides=(S*n,n))
def pattern_index_broadcasting(all_data, search_data):
n = len(search_data)
all_data = np.asarray(all_data)
all_data_2D = strided_app(np.asarray(all_data), n, S=1)
return np.flatnonzero((all_data_2D == search_data).all(1))
out = np.squeeze(pattern_index_broadcasting(l, m)[:,None] + np.arange(len(m)))
示例运行 -
In [340]: l = [5,6,7,8,9,10,5,15,20,50,16,18]
...: m = [10,5,15,20]
...:
In [341]: np.squeeze(pattern_index_broadcasting(l, m)[:,None] + np.arange(len(m)))
Out[341]: array([5, 6, 7, 8])
In [342]: l = [5,6,7,8,9,10,5,15,20,50,16,18,10,5,15,20]
...: m = [10,5,15,20]
...:
In [343]: np.squeeze(pattern_index_broadcasting(l, m)[:,None] + np.arange(len(m)))
Out[343]:
array([[ 5, 6, 7, 8],
[12, 13, 14, 15]])
方法二: 另一种方法是获取滑动窗口,然后将数据按行标量视图分成要搜索的数据和要搜索的数据,从而给我们提供 1D
数据来处理,如下所示 -
def view1D(a, b):
a = np.ascontiguousarray(a)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(void_dt).ravel(), b.view(void_dt).ravel()
def pattern_index_view1D(all_data, search_data):
a = strided_app(np.asarray(all_data), L=len(search_data), S=1)
a0v, b0v = view1D(np.asarray(a), np.asarray(search_data))
return np.flatnonzero(np.in1d(a0v, b0v))
out = np.squeeze(pattern_index_view1D(l, m)[:,None] + np.arange(len(m)))
2020年版本
为了寻求更简单/紧凑的方法,我们可以查看scikit-image的view_as_windows
,以获取带有内置的滑动窗口。我假设数组作为输入以获取更清晰的代码。对于列表作为输入,我们必须使用np.asarray()
,如前所示。
方法 # 3:基本上是将pattern_index_broadcasting
与view_as_windows
导出为一个包含 a
作为较大数据和b
作为要搜索的数组的一行代码-
from skimage.util import view_as_windows
np.flatnonzero((view_as_windows(a,len(b))==b).all(1))[:,None]+np.arange(len(b))
方案 #4 : 对于从b
到a
的少量匹配,我们可以优化,通过查找b
的第一个元素匹配来减少搜索的数据集大小 -
mask = a[:-len(b)+1]==b[0]
mask[mask] = (view_as_windows(a,len(b))[mask]).all(1)
out = np.flatnonzero(mask)[:,None]+np.arange(len(b))
方法#5: 对于小型的b
,我们可以简单地为b
中的每个元素运行一个循环,并执行按位与-规约
操作 -
mask = np.bitwise_and.reduce([a[i:len(a)-len(b)+1+i]==b[i] for i in range(len(b))])
out = np.flatnonzero(mask)[:,None]+np.arange(len(b))
5
。 - Jon Clements