Python 如何获取另一个列表中某个列表项的索引?

Python 如何获取另一个列表中某个列表项的索引?,python,list,numpy,Python,List,Numpy,假设我有以下清单: l = [5,6,7,8,9,10,5,15,20] m = [10,5] 我想在l中获得m的索引。我使用列表理解来实现这一点: [(i,i+1) for i,j in enumerate(l) if m[0] == l[i] and m[1] == l[i+1]] 输出:[(5,6)] 但是如果我在m中有更多的数字,我觉得这不是正确的方法。那么,在Python或NumPy中有什么简单的方法吗 另一个例子: l = [5,6,7,8,9,10,5,15,20,50,16,

假设我有以下清单:

l = [5,6,7,8,9,10,5,15,20]
m = [10,5]
我想在
l
中获得
m
的索引。我使用列表理解来实现这一点:

[(i,i+1) for i,j in enumerate(l) if m[0] == l[i] and m[1] == l[i+1]]
输出:
[(5,6)]

但是如果我在
m
中有更多的数字,我觉得这不是正确的方法。那么,在Python或NumPy中有什么简单的方法吗

另一个例子:

l = [5,6,7,8,9,10,5,15,20,50,16,18]
m = [10,5,15,20]
输出应为:

[(5,6,7,8)]

您基本上是在另一个列表中查找列表的起始索引

方法#1:解决方法之一是在我们正在搜索的列表中创建元素的滑动窗口,给我们一个
2D
数组,然后简单地使用
NumPy broadcasting
对搜索列表中先前获得的
2D
滑动窗口版本的每一行执行广播比较。因此,一种方法是-

# strided_app is from https://stackoverflow.com/a/40085052/
def strided_app(a, L, S ):  # Window len = L, Stride len/stepsize = 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]])
方法#2:另一种方法是获得滑动窗口,然后获得要搜索的数据和要搜索的数据的行级标量视图,这样我们就可以使用
1D
数据,如下所示-

# view1D is from https://stackoverflow.com/a/45313353/
def view1D(a, b): # a, b are arrays
    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图像的内置滑动窗口。我假设数组作为不太混乱的代码的输入。对于作为输入的列表,我们必须使用
np.asarray()
,如前所示

方法#3:基本上是
模式(pattern)索引(broadcasting)
的一种派生方法以
视图(u as)窗口
为一行,其中
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:对于
a
b
中的少量匹配,我们可以通过从
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))
最简单的方法(使用纯Python)是迭代这些项,然后首先只检查第一个项是否匹配。这样可以避免在不需要时进行子列表比较。根据
l
的内容,这可能会比NumPy广播解决方案更出色:

def func(haystack, needle):  # obviously needs a better name ...
    if not needle:
        return
    # just optimization
    lengthneedle = len(needle)
    firstneedle = needle[0]
    for idx, item in enumerate(haystack):
        if item == firstneedle:
            if haystack[idx:idx+lengthneedle] == needle:
                yield tuple(range(idx, idx+lengthneedle))

>>> list(func(l, m))
[(5, 6, 7, 8)]
如果您对速度感兴趣,我会检查进近的性能(借用我的设置):

如果您的
l
m
是列表,我的功能在所有尺寸上都优于NumPy解决方案:

但是,如果您将这些作为numpy阵列,那么在使用Divakars numpy解决方案时,对于大型阵列(大小>1000个元素),您将获得更快的结果:

def func(haystack, needle):  # obviously needs a better name ...
    if not needle:
        return
    # just optimization
    lengthneedle = len(needle)
    firstneedle = needle[0]
    for idx, item in enumerate(haystack):
        if item == firstneedle:
            if haystack[idx:idx+lengthneedle] == needle:
                yield tuple(range(idx, idx+lengthneedle))

>>> list(func(l, m))
[(5, 6, 7, 8)]

只是强调@MSeifert的方法当然也可以在
numpy
中实现:

def pp(h,n):
    nn = len(n)
    NN = len(h)
    c = (h[:NN-nn+1]==n[0]).nonzero()[0]
    if c.size==0: return
    for i,l in enumerate(n[1:].tolist(),1):
        c = c[h[i:][c]==l]
        if c.size==0: return
    return np.arange(c[0],c[0]+nn)

在多次出现的情况下,索引值应该是多少<代码>5在您的示例中…我希望它按特定顺序检查列表。如果没有找到订单,ohk会有一个空的列表。我不确定副本是否能解决您的问题。如果没有,请告诉我。:)被NumPy标记后,您可能希望利用它的矢量化功能。重新打开,是的。我想要的是numpy数组方法。它是如此精确和快速。它以纳秒为单位输出。哇。先生,如果我想得到所有的重复序列,而不是第一个。@Bharathshetty将
np.argmax
替换为
np.flatnonzero
。让我来编辑。@Bharathshetty就像我说的,让我来编辑:)编辑完成后告诉我:)他们都很好,先生。第一种方法比第二种方法快一点。基准图非常好。非常感谢你的链接。我在我这边已经证实了这一点,但是矢量化解决方案的阈值变得更好了,在我这边的200个元素上,阵列数据。我不得不使用
列表(查找子列表\u索引(a,b))
,以确保我们正在做同样的事情。@divaker你说得对。我混合了我的函数(列表)的最快情况和你的函数(数组)的最快情况。请注意,如果要将数组转换为列表,则
tolist
将比
list
快得多(在大多数情况下,系数为2-5)。如果您对所有函数的numpy数组都感兴趣,我将在稍后更新答案。:)