如何在列表中找到给定项的索引?

4389 投票
46 回答
6316987 浏览
提问于 2025-04-11 09:27

假设你有一个列表,里面有三个元素:["foo", "bar", "baz"]。现在你想找到其中一个元素"bar"的位置,也就是它在列表中的索引。这个索引是1,因为列表的第一个元素是"foo",第二个元素是"bar"

46 个回答

242

要获取所有的索引:

indexes = [i for i, x in enumerate(xs) if x == 'foo']
713

大多数回答都在讲怎么找到一个索引,但是它们的方法如果列表中有多个相同的项,就不能返回多个索引。可以使用enumerate()来解决这个问题:

for i, j in enumerate(['foo', 'bar', 'baz']):
    if j == 'bar':
        print(i)

index()这个函数只会返回第一个出现的索引,而enumerate()则会返回所有出现的索引。

用列表推导式的写法:

[i for i, j in enumerate(['foo', 'bar', 'baz']) if j == 'bar']

这里还有一个小的解决方案,使用itertools.count()(这个方法和enumerate的思路差不多):

from itertools import izip as zip, count # izip for maximum efficiency
[i for i, j in zip(count(), ['foo', 'bar', 'baz']) if j == 'bar']

对于较大的列表,这种方法比使用enumerate()更高效:

$ python -m timeit -s "from itertools import izip as zip, count" "[i for i, j in zip(count(), ['foo', 'bar', 'baz']*500) if j == 'bar']"
10000 loops, best of 3: 174 usec per loop
$ python -m timeit "[i for i, j in enumerate(['foo', 'bar', 'baz']*500) if j == 'bar']"
10000 loops, best of 3: 196 usec per loop
5977
>>> ["foo", "bar", "baz"].index("bar")
1

查看文档,了解列表的内置.index()方法:

list.index(x[, start[, end]])

这个方法会返回列表中第一个值等于x的项的索引,索引是从0开始的。如果没有找到这样的项,就会抛出一个ValueError错误。

可选的startend参数可以用来限制搜索范围,类似于切片表示法。返回的索引是相对于整个列表的开头,而不是start参数的位置。

注意事项

列表长度的线性时间复杂度

调用index方法时,会逐个检查列表中的每个元素,直到找到匹配的项。如果列表很长,并且没有保证要找的值在前面,这样会导致代码变慢。

要完全避免这个问题,必须使用不同的数据结构。不过,如果知道要找的元素在列表的某个特定部分,可以使用startend参数来缩小搜索范围。

例如:

>>> import timeit
>>> timeit.timeit('l.index(999_999)', setup='l = list(range(0, 1_000_000))', number=1000)
9.356267921015387
>>> timeit.timeit('l.index(999_999, 999_990, 1_000_000)', setup='l = list(range(0, 1_000_000))', number=1000)
0.0004404920036904514

第二次调用速度快得多,因为它只需要搜索10个元素,而不是全部100万个。

只返回第一个匹配项的索引

调用index方法时,会顺序搜索列表,直到找到匹配项,然后就停止了。如果可能有多个相同的值,并且需要所有的索引,index方法就无法解决这个问题:

>>> [1, 1].index(1) # the `1` index is not found.
0

相反,可以使用列表推导或生成器表达式来进行搜索,并结合enumerate来获取索引

>>> # A list comprehension gives a list of indices directly:
>>> [i for i, e in enumerate([1, 2, 1]) if e == 1]
[0, 2]
>>> # A generator comprehension gives us an iterable object...
>>> g = (i for i, e in enumerate([1, 2, 1]) if e == 1)
>>> # which can be used in a `for` loop, or manually iterated with `next`:
>>> next(g)
0
>>> next(g)
2

如果只有一个匹配项,列表推导和生成器表达式的方法依然有效,而且更具通用性。

如果没有匹配项会抛出异常

如上文档所述,如果使用.index方法查找的值不在列表中,会抛出异常:

>>> [1, 1].index(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 2 is not in list

如果这让你担心,可以先显式检查一下,使用item in my_list,或者根据需要使用try/except来处理异常。

显式检查简单易懂,但需要第二次遍历列表。有关这个选择的更多指导,请参见Python中的EAFP原则是什么?

撰写回答