Вопрос-Ответ

How to find the index for a given item in a list?

Как найти индекс для данного элемента в списке?

Учитывая список ["foo", "bar", "baz"] и элемент в списке "bar", как мне получить его индекс 1?

Переведено автоматически
Ответ 1
>>> ["foo", "bar", "baz"].index("bar")
1

Смотрите документацию для встроенного .index() метода списка:


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

Возвращает нулевой индекс в списке первого элемента, значение которого равно x. Вызывает a ValueError, если такого элемента нет.


Необязательные аргументы start и end интерпретируются как в нотации среза и используются для ограничения поиска определенной подпоследовательностью списка. Возвращаемый индекс вычисляется относительно начала полной последовательности, а не начального аргумента.


Предостережения

Линейная временная сложность в длине списка

Вызов 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 элементам, а не по всем 1 миллиону.

Возвращается только индекс первого совпадения

Вызов 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 соответственно.

Явная проверка проста и удобочитаема, но она должна повторять список второй раз. Смотрите Что такое принцип EAFP в Python? для получения дополнительных рекомендаций по этому выбору.

Ответ 2

В большинстве ответов объясняется, как найти один индекс, но их методы не возвращают несколько индексов, если элемент находится в списке несколько раз. Использовать 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
Ответ 3

Чтобы получить все индексы:

indexes = [i for i, x in enumerate(xs) if x == 'foo']
Ответ 4

index() возвращает первый индекс значения!


| индекс(...)
| L.индекс(значение, [start, [stop]]) -> целое число - возвращает первый индекс значения


def all_indices(value, qlist):
indices = []
idx = -1
while True:
try:
idx = qlist.index(value, idx+1)
indices.append(idx)
except ValueError:
break
return indices

all_indices("foo", ["foo","bar","baz","foo"])
python list