如何在列表中找到给定项的索引?
假设你有一个列表,里面有三个元素:["foo", "bar", "baz"]
。现在你想找到其中一个元素"bar"
的位置,也就是它在列表中的索引。这个索引是1
,因为列表的第一个元素是"foo"
,第二个元素是"bar"
。
46 个回答
要获取所有的索引:
indexes = [i for i, x in enumerate(xs) if x == 'foo']
大多数回答都在讲怎么找到一个索引,但是它们的方法如果列表中有多个相同的项,就不能返回多个索引。可以使用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
>>> ["foo", "bar", "baz"].index("bar")
1
查看文档,了解列表的内置.index()
方法:
list.index(x[, start[, end]])
这个方法会返回列表中第一个值等于x的项的索引,索引是从0开始的。如果没有找到这样的项,就会抛出一个
ValueError
错误。可选的start和end参数可以用来限制搜索范围,类似于切片表示法。返回的索引是相对于整个列表的开头,而不是start参数的位置。
注意事项
列表长度的线性时间复杂度
调用index
方法时,会逐个检查列表中的每个元素,直到找到匹配的项。如果列表很长,并且没有保证要找的值在前面,这样会导致代码变慢。
要完全避免这个问题,必须使用不同的数据结构。不过,如果知道要找的元素在列表的某个特定部分,可以使用start
和end
参数来缩小搜索范围。
例如:
>>> 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原则是什么?。