在Python中查找列表中匹配元素的索引

51

我有一个由1到5的浮点数组成的长列表叫做"average",我想返回其中小于a或大于b的元素的索引列表。

def find(lst,a,b):
    result = []
    for x in lst:
        if x<a or x>b:
            i = lst.index(x)
            result.append(i)
    return result

matches = find(average,2,4)

但是令人惊讶的是,"matches" 的输出结果中有很多重复,例如[2, 2, 10, 2, 2, 2, 19, 2, 10, 2, 2, 42, 2, 2, 10, 2, 2, 2, 10, 2, 2, ...]

为什么会出现这种情况呢?


3个回答

81
你正在使用 .index() 方法,它只能找到列表中第一个值的位置。因此,如果你在索引2和索引9处都有1.0这个值,那么无论列表中出现了多少次1.0,.index(1.0) 总是会返回 2
改用 enumerate() 方法来为循环添加索引:
def find(lst, a, b):
    result = []
    for i, x in enumerate(lst):
        if x<a or x>b:
            result.append(i)
    return result

您可以将此转换为列表推导式:
def find(lst, a, b):
    return [i for i, x in enumerate(lst) if x<a or x>b]

现在我完全明白了。列表推导式确实很好,我仍在努力适应Python中这种紧凑的形式。你的回答非常出色,非常感谢! - Logan Yang
有趣的是,带有重复的错误结果似乎对我的后续使用很有效,因为我想用它来提取一个大矩阵的列。看起来重复不会影响切片。 - Logan Yang
1
你仍然可以从列表中获取正确的值,相同的值位于索引2和后面的任何索引处。但这是一个等待发生的错误,在代码的某些其他点会咬你一口。 - Martijn Pieters

3

如果您需要频繁进行这种操作,建议使用numpy

In [56]: import random, numpy

In [57]: lst = numpy.array([random.uniform(0, 5) for _ in range(1000)]) # example list

In [58]: a, b = 1, 3

In [59]: numpy.flatnonzero((lst > a) & (lst < b))[:10]
Out[59]: array([ 0, 12, 13, 15, 18, 19, 23, 24, 26, 29])

为了回答Seanny123的问题,我使用了以下计时代码:
import numpy, timeit, random

a, b = 1, 3

lst = numpy.array([random.uniform(0, 5) for _ in range(1000)])

def numpy_way():
    numpy.flatnonzero((lst > 1) & (lst < 3))[:10]

def list_comprehension():
    [e for e in lst if 1 < e < 3][:10]

print timeit.timeit(numpy_way)
print timeit.timeit(list_comprehension)

numpy版本速度超过原来的60倍。

与仅使用列表推导相比,性能如何?此外,为什么要使用 numpy.flatnonzero 而不是 numpy.where - Seanny123
1
在我的手中,它的速度快了60倍。flatnonzerowhere更简单;你不需要将索引数组从元组中提取出来。 - Alex Coventry

-2
>>> average =  [1,3,2,1,1,0,24,23,7,2,727,2,7,68,7,83,2]
>>> matches = [i for i in range(0,len(average)) if average[i]<2 or average[i]>4]
>>> matches
[0, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15]

这完全不是原帖作者所想要的。 - TerryA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接