在列表中查找元素的索引

26 浏览
0 Comments

在列表中查找元素的索引

假设有一个列表[\"foo\", \"bar\", \"baz\"]和列表中的一个元素\"bar\",我该如何获取它的索引1

admin 更改状态以发布 2023年5月20日
0
0 Comments

大多数答案都解释了如何找到单个索引,但它们的方法如果该项在列表中出现多次,则不会返回多个索引。使用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

0
0 Comments

>>> ["foo", "bar", "baz"].index("bar")
1

请参阅文档中的内置.index()方法的说明:

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

返回列表中第一个值等于x的元素的基于零的索引。如果不存在这样的元素,则会引发ValueError异常。

可选参数start和end的解释与切片符号中的相同,并用于限制搜索到列表的特定子序列。返回的索引是相对于完整序列的开头而不是开始参数计算的。

注意事项

线性时间复杂度

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 "", line 1, in 
ValueError: 2 is not in list

如果这是一个问题,可以使用 item in my_list 显式地进行第一次检查,或根据需要使用 try/except 来处理异常。

显式检查简单易读,但必须第二次迭代列表。有关此选择的更多指导,请参见 Python 中的 EAFP 原则是什么?

0