Как найти первое вхождение элемента в список

Finding the index of an item given a list containing it in Python

For a list ["foo", "bar", "baz"] and an item in the list "bar", what’s the cleanest way to get its index (1) in Python?

Well, sure, there’s the index method, which returns the index of the first occurrence:

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

There are a couple of issues with this method:

  • if the value isn’t in the list, you’ll get a ValueError
  • if more than one of the value is in the list, you only get the index for the first one

No values

If the value could be missing, you need to catch the ValueError.

You can do so with a reusable definition like this:

def index(a_list, value):
    try:
        return a_list.index(value)
    except ValueError:
        return None

And use it like this:

>>> print(index(l, 'quux'))
None
>>> print(index(l, 'bar'))
1

And the downside of this is that you will probably have a check for if the returned value is or is not None:

result = index(a_list, value)
if result is not None:
    do_something(result)

More than one value in the list

If you could have more occurrences, you’ll not get complete information with list.index:

>>> l.append('bar')
>>> l
['foo', 'bar', 'baz', 'bar']
>>> l.index('bar')              # nothing at index 3?
1

You might enumerate into a list comprehension the indexes:

>>> [index for index, v in enumerate(l) if v == 'bar']
[1, 3]
>>> [index for index, v in enumerate(l) if v == 'boink']
[]

If you have no occurrences, you can check for that with boolean check of the result, or just do nothing if you loop over the results:

indexes = [index for index, v in enumerate(l) if v == 'boink']
for index in indexes:
    do_something(index)

Better data munging with pandas

If you have pandas, you can easily get this information with a Series object:

>>> import pandas as pd
>>> series = pd.Series(l)
>>> series
0    foo
1    bar
2    baz
3    bar
dtype: object

A comparison check will return a series of booleans:

>>> series == 'bar'
0    False
1     True
2    False
3     True
dtype: bool

Pass that series of booleans to the series via subscript notation, and you get just the matching members:

>>> series[series == 'bar']
1    bar
3    bar
dtype: object

If you want just the indexes, the index attribute returns a series of integers:

>>> series[series == 'bar'].index
Int64Index([1, 3], dtype='int64')

And if you want them in a list or tuple, just pass them to the constructor:

>>> list(series[series == 'bar'].index)
[1, 3]

Yes, you could use a list comprehension with enumerate too, but that’s just not as elegant, in my opinion – you’re doing tests for equality in Python, instead of letting builtin code written in C handle it:

>>> [i for i, value in enumerate(l) if value == 'bar']
[1, 3]

Is this an XY problem?

The XY problem is asking about your attempted solution rather than your actual problem.

Why do you think you need the index given an element in a list?

If you already know the value, why do you care where it is in a list?

If the value isn’t there, catching the ValueError is rather verbose – and I prefer to avoid that.

I’m usually iterating over the list anyways, so I’ll usually keep a pointer to any interesting information, getting the index with enumerate.

If you’re munging data, you should probably be using pandas – which has far more elegant tools than the pure Python workarounds I’ve shown.

I do not recall needing list.index, myself. However, I have looked through the Python standard library, and I see some excellent uses for it.

There are many, many uses for it in idlelib, for GUI and text parsing.

The keyword module uses it to find comment markers in the module to automatically regenerate the list of keywords in it via metaprogramming.

In Lib/mailbox.py it seems to be using it like an ordered mapping:

key_list[key_list.index(old)] = new

and

del key_list[key_list.index(key)]

In Lib/http/cookiejar.py, seems to be used to get the next month:

mon = MONTHS_LOWER.index(mon.lower())+1

In Lib/tarfile.py similar to distutils to get a slice up to an item:

members = members[:members.index(tarinfo)]

In Lib/pickletools.py:

numtopop = before.index(markobject)

What these usages seem to have in common is that they seem to operate on lists of constrained sizes (important because of O(n) lookup time for list.index), and they’re mostly used in parsing (and UI in the case of Idle).

While there are use-cases for it, they are fairly uncommon. If you find yourself looking for this answer, ask yourself if what you’re doing is the most direct usage of the tools provided by the language for your use-case.

Изучая программирование на Python, вы практически в самом начале знакомитесь со списками и различными операциями, которые можете выполнять над ними. В этой статье мы бы хотели рассказать об одной из таких операций над списками.

Представьте, что у вас есть список, состоящий из каких-то элементов, и вам нужно определить индекс элемента со значением x. Сегодня мы рассмотрим, как узнать индекс определенного элемента списка в Python.

Но сначала давайте убедимся, что все  понимают, что представляет из себя список.

Список в Python — это встроенный тип данных, который позволяет нам хранить множество различных значений, таких как числа, строки, объекты datetime и так далее.

Важно отметить, что списки упорядочены. Это означает, что последовательность, в которой мы храним значения, важна.

Индексирование списка начинаются с нуля и заканчивается на длине списка минус один. Для получения более подробной информации о списках вы можете обратиться к статье «Списки в Python: полное руководство для начинающих».

Итак, давайте посмотрим на пример списка:

fruits = ["apple", "orange","grapes","guava"]
print(type(fruits))
print(fruits[0])
print(fruits[1])
print(fruits[2])

# Результат:
# <class 'list'>
# apple
# orange
# grapes

Мы создали список из 4 элементов. Первый элемент в списке имеет нулевой индекс, второй элемент — индекс 1, третий элемент — индекс 2, а последний — 3.

Для списка получившихся фруктов fruits допустимыми индексами являются 0, 1, 2 и 3. При этом длина списка равна 4 (в списке 4 элемента). Индекс последнего элемента равен длине списка (4) минус один, то есть как раз 3.

[python_ad_block]

Как определить индекс элемента списка в Python

Итак, как же определить индекс элемента в Python? Давайте представим, что у нас есть элемент списка и нам нужно узнать индекс или позицию этого элемента. Сделать это можно следующим образом:

print(fruits.index('orange'))
# 1

print(fruits.index('guava'))
# 3

print(fruits.index('banana'))
# А здесь выскочит ValueError, потому что в списке нет значения banana

Списки Python предоставляют нам метод index(), с помощью которого можно получить индекс первого вхождения элемента в список, как это показано выше.

Познакомиться с другими методами списков можно в статье «Методы списков Python».

Мы также можем заметить, что метод index() вызовет ошибку VauleError, если мы попытаемся определить индекс элемента, которого нет в исходном списке.

Для получения более подробной информации о методе index() загляните в официальную документацию.

Базовый синтаксис метода index() выглядит так:

list_var.index(item),

где list_var — это исходный список,   item — искомый элемент.

Мы также можем указать подсписок для поиска, и синтаксис для этого будет выглядеть следующим образом:

list_var.index(item, start_index_of_sublist, end_index_of_sublist)

Здесь добавляются два аргумента: start_index_of_sublist и end_index_of_sublist. Тут всё просто. start_index_of_sublist обозначает, с какого элемента списка мы хотим начать поиск, а end_index_of_sublist, соответственно, на каком элементе (не включительно) мы хотим закончить.

Чтобы проиллюстрировать это для лучшего понимания, давайте рассмотрим следующий пример.

Предположим, у нас есть список book_shelf_genres, где индекс означает номер полки (индексация начинается с нуля). У нас много полок, среди них есть и полки с учебниками по математике.

Мы хотим узнать, где стоят учебники по математике, но не вообще, а после четвертой полки. Для этого напишем следующую программу:

book_shelf_genres = ["Fiction", "Math", "Non-fiction", "History", "Math", "Coding", "Cooking", "Math"]
print(book_shelf_genres.index("Math"))
# Результат:
# 1

Здесь мы видим проблему. Использование просто метода index() без дополнительных аргументов выдаст первое вхождение элемента в список, но мы хотим знать индекс значения «Math» после полки 4.

Для этого мы используем метод index() и указываем подсписок для поиска. Подсписок начинается с индекса 5 до конца списка book_shelf_genres, как это показано во фрагменте кода ниже:

print(book_shelf_genres.index("Math", 5))
# Результат:
# 7

Обратите внимание, что указывать конечный индекс подсписка необязательно.

Чтобы вывести индекс элемента «Math» после полки номер 1 и перед полкой номер 5, мы просто напишем следующее:

print(book_shelf_genres.index("Math", 2, 5))
# Результат:
# 4

Как найти индексы всех вхождений элемента в списке

А что, если искомое значение встречается в списке несколько раз и мы хотим узнать индексы всех этих элементов? Метод index() выдаст нам индекс только первого вхождения.

В этом случае мы можем использовать генератор списков:

book_shelf_genres = ["Fiction", "Math", "Non-fiction", "History", "Math", "Coding", 
                     "Cooking", "Math"]

indices = [i for i in range(0, len(book_shelf_genres)) if book_shelf_genres[i]=="Math"]
print(indices)

# Результат:
# [1, 4, 7]

В этом фрагменте кода мы перебираем индексы списка в цикле for и при помощи range(). Далее мы проверяем значение элемента под каждым индексом на равенство «Math«. Если значение элемента — «Math«, мы сохраняем значение индекса в списке.

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

Подробнее про генераторы списков можно почитать в статье «Генераторы списков в Python для начинающих».

Благодаря генератору мы получили все номера полок, на которых стоят книги по математике.

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

Теперь представьте ситуацию, что у вас есть вложенный список, то есть список, состоящий из других списков. И ваша задача — определить индекс искомого элемента для каждого из подсписков. Сделать это можно следующим образом:

programming_languages = [["C","C++","Java"],
                         ["Python","Rust","R"],
                         ["JavaScript","Prolog","Python"]]

indices = [(i, x.index("Python")) for i, x in enumerate(programming_languages) if "Python" in x]
print(indices)

# Результат:
# [(1, 0), (2, 2)]

Здесь мы используем генератор списков и метод index(), чтобы найти индексы элементов со значением «Python» в каждом из имеющихся подсписков. Что же делает этот код?

Мы передаем список programming_languages ​​методу enumerate(), который просматривает каждый элемент в списке и возвращает кортеж, содержащий индекс и значение элемента списка.

Каждый элемент в списке programming_languages ​​также является списком. Оператор in проверяет, присутствует ли элемент «Python» в этом списке. Если да — мы сохраняем индекс подсписка и индекс элемента «Python» внутри подсписка в виде кортежа.

Результатом программы, как вы можете видеть, является список кортежей. Первый элемент кортежа — индекс подсписка, а второй — индекс искомого элемента в этом подсписке.

Таким образом, (1,0) означает, что подсписок с индексом 1 списка programming_languages ​​имеет элемент «Python», который расположен по индексу 0. То есть, говоря простыми словами, второй подсписок содержит искомый элемент и этот элемент стоит на первом месте. Не забываем, что в Python индексация идет с нуля.

Как искать индекс элемента, которого, возможно, нет в списке

Бывает, нужно получить индекс элемента, но мы не уверены, есть ли он в списке.

Если попытаться получить индекс элемента, которого нет в списке, метод index() вызовет ошибку ValueError. При отсутствии обработки исключений ValueError вызовет аварийное завершение программы. Такой исход явно не является хорошим и с ним нужно что-то сделать.

Вот два способа, с помощью которых мы можем избежать такой ситуации:

books = ["Cracking the Coding Interview", "Clean Code", "The Pragmatic Programmer"]
ind = books.index("The Pragmatic Programmer") if "The Pragmatic Programmer" in books else -1
print(ind)

# Результат:
# 2

Один из способов — проверить с помощью оператора in, есть ли элемент в списке. Оператор in имеет следующий синтаксис:

var in iterable

Итерируемый объект — iterable — может быть списком, кортежем, множеством, строкой или словарем. Если var существует как элемент в iterable, оператор in возвращает значение True. В противном случае он возвращает False.

Это идеально подходит для решения нашей проблемы. Мы просто проверим, есть ли элемент в списке, и вызовем метод index() только если элемент существует. Это гарантирует, что метод index() не вызовет нам ошибку ValueError.

Но если мы не хотим тратить время на проверку наличия элемента в списке (это особенно актуально для больших списков), мы можем обработать ValueError следующим образом:

books = ["Cracking the Coding Interview", "Clean Code", "The Pragmatic Programmer"]
try:
    ind = books.index("Design Patterns")
except ValueError:
    ind = -1
print(ind)

# Результат:
# -1

Здесь мы применили конструкцию try-except для обработки ошибок. Программа попытается выполнить блок, стоящий после слова try. Если это приведет к ошибке ValueError, то она выполнит блок после ключевого слова except. Подробнее про обработку исключений с помощью try-except можно почитать в статье «Обрабатываем исключения в Python: try и except».

Заключение

Итак, мы разобрали как определить индекс элемента списка в Python. Теперь вы знаете, как это сделать с помощью метода index() и генератора списков.

Мы также разобрали, как использовать метод index() для вложенных списков и как найти каждое вхождение элемента в списке. Кроме того, мы рассмотрели ситуацию, когда нужно найти индекс элемента, которого, возможно, нет в списке.

Мы надеемся, что данная статья была для вас полезной. Успехов в написании кода!

Больше 50 задач по Python c решением и дискуссией между подписчиками можно посмотреть тут

Перевод статьи «Python Index – How to Find the Index of an Element in a List».

Perhaps the two most efficient ways to find the last index:

def rindex(lst, value):
    lst.reverse()
    i = lst.index(value)
    lst.reverse()
    return len(lst) - i - 1
def rindex(lst, value):
    return len(lst) - operator.indexOf(reversed(lst), value) - 1

Both take only O(1) extra space and the two in-place reversals of the first solution are much faster than creating a reverse copy. Let’s compare it with the other solutions posted previously:

def rindex(lst, value):
    return len(lst) - lst[::-1].index(value) - 1

def rindex(lst, value):
    return len(lst) - next(i for i, val in enumerate(reversed(lst)) if val == value) - 1

Benchmark results, my solutions are the red and green ones:
unshuffled, full range

This is for searching a number in a list of a million numbers. The x-axis is for the location of the searched element: 0% means it’s at the start of the list, 100% means it’s at the end of the list. All solutions are fastest at location 100%, with the two reversed solutions taking pretty much no time for that, the double-reverse solution taking a little time, and the reverse-copy taking a lot of time.

A closer look at the right end:
unshuffled, tail part

At location 100%, the reverse-copy solution and the double-reverse solution spend all their time on the reversals (index() is instant), so we see that the two in-place reversals are about seven times as fast as creating the reverse copy.

The above was with lst = list(range(1_000_000, 2_000_001)), which pretty much creates the int objects sequentially in memory, which is extremely cache-friendly. Let’s do it again after shuffling the list with random.shuffle(lst) (probably less realistic, but interesting):

shuffled list, full range

shuffled list, tail part

All got a lot slower, as expected. The reverse-copy solution suffers the most, at 100% it now takes about 32 times (!) as long as the double-reverse solution. And the enumerate-solution is now second-fastest only after location 98%.

Overall I like the operator.indexOf solution best, as it’s the fastest one for the last half or quarter of all locations, which are perhaps the more interesting locations if you’re actually doing rindex for something. And it’s only a bit slower than the double-reverse solution in earlier locations.

All benchmarks done with CPython 3.9.0 64-bit on Windows 10 Pro 1903 64-bit.

Списки полезны по-разному по сравнению с другими типами данных из-за их универсальности. В этой статье мы рассмотрим одну из самых распространенных операций со списками – поиск индекса элемента.

Мы рассмотрим различные сценарии поиска элемента, то есть нахождение первого, последнего и всех вхождений элемента. А также что происходит, когда искомого элемента не существует.

Использование Функции&nbsp;index()

Все операции, упомянутые в предыдущем абзаце, можно выполнить с помощью встроенной функции index(). Синтаксис этой функции:

index(element[, start[, end]])

Параметр element, естественно, представляет собой элемент который мы ищем. Параметры start и end являются необязательными и представляют диапазон индексов, в котором мы ищем element.

Значение по умолчанию для start0 (поиск с начала), а значение по умолчанию для end – это количество элементов в списке (поиск до конца списка).

Функция возвращает первую позицию element в списке, которую она могла найти, независимо от того, сколько равных элементов осталось после первого вхождения.

Нахождение первого появления элемента

Использование функции index() без установки каких-либо значений для start и end даст нам первое вхождение искомого element:

my_list = ['a', 'b', 'c', 'd', 'e', '1', '2', '3', 'b']

first_occurrence = my_list.index('b')
print("First occurrence of 'b' in the list: ", first_occurrence)

Что даст нам ожидаемый результат:

First occurrence of 'b' in the list: 1

Поиск всех вхождений элемента

Чтобы найти все вхождения элемента, мы можем использовать необязательный параметр start, чтобы мы выполняли поиск только в определенных сегментах списка.

Например, предположим, что первое вхождение элемента в index 3. Чтобы найти следующий, нам нужно будет продолжить поиск первого появления этого элемента после индекса 3. Мы будем повторять этот процесс, меняя место начала поиска, пока мы найдем новые вхождения элемента:

my_list = ['b', 'a', 2, 'n', False, 'a', 'n', 'a']

all_occurrences = []
last_found_index = -1
element_found = True

while element_found:
    try:
        last_found_index = my_list.index('a', last_found_index + 1)
        all_occurrences.append(last_found_index)
    except ValueError:
        element_found = False
    
if len(all_occurrences) == 0:
    print("The element wasn't found in the list")
else:
    print("The element was found at: " + str(all_occurrences))

Запуск этого кода даст нам:

The element was found at: [1, 5, 7]

Здесь нам пришлось использовать блок try, так как функция index() выдает ошибку, когда не может найти указанный element в заданном диапазоне. Это может быть необычно для разработчиков, которые больше привыкли к другим языкам, поскольку такие функции обычно возвращают -1 / null, когда элемент не может быть найден.

Однако в Python мы должны быть осторожны и использовать блок try при использовании этой функции.

Другой, более изящный способ сделать то же самое – использовать понимание списка и полностью игнорировать функцию index():

my_list = ['b', 'a', 2, 'n', False, 'a', 'n', 'a']

all_occurrences = [index for index, element in enumerate(my_list) if element == 'a']

print("The element was found at: " + str(all_occurrences))

Что даст нам тот же результат, что и раньше. У этого подхода есть дополнительное преимущество в том, что он не использует блок try.

Нахождение последнего появления элемента

Если вам нужно найти последнее вхождение элемента в списке, есть два подхода, которые вы можете использовать с функцией index():

  1. Переверните список и найдите первое вхождение в перевернутом списке
  2. Просмотрите все вхождения элемента и отслеживайте только последнее вхождение

Что касается первого подхода, если бы мы знали первое вхождение element в обратном списке, мы могли бы найти позицию последнего вхождения в исходном. В частности, мы можем сделать это, вычтя reversed_list_index - 1 из длины исходного списка:

my_list = ['b', 'a', 2, 'n', False, 'a', 'n', 'a']

reversed_list_index = my_list[::-1].index('n')
# or alteratively:
# reversed_list_index2 = list(reversed(my_list)).index('n')

original_list_index = len(my_list) - 1 - reversed_list_index

print(original_list_index)

Что даст нам желаемый результат:

Что касается второго подхода, мы могли бы настроить код, который мы использовали, чтобы найти все вхождения, и отслеживать только последнее обнаруженное вхождение:

my_list = ['b', 'a', 2, 'n', False, 'a', 'n', 'a']

last_occurrence = -1
element_found = True

while element_found:
    try:
        last_occurrence = my_list.index('n', last_occurrence + 1)
    except ValueError:
        element_found = False
    
if last_occurrence == -1:
    print("The element wasn't found in the list")
else:
    print("The last occurrence of the element is at: ", last_occurrence)

Что даст нам тот же результат:

Вывод

Мы рассмотрели некоторые из наиболее распространенных способов использования функции index() и способы избежать ошибки в некоторых случаях.

Помните о потенциально необычном поведении функции index(), когда она выдает ошибку вместо возврата -1 / None, когда элемент не найден в списке.

Чтобы найти индекс первого вхождения элемента в данном списке в Python, вы можете использовать метод index() класса List с элементом, переданным в качестве аргумента.

index = mylist.index(element)

Метод index() возвращает целое число, представляющее индекс первого совпадения указанного элемента в списке.

Вы также можете указать начальную и конечную позиции списка, где должен происходить поиск в списке.

Ниже приводится синтаксис функции index() с начальной и конечной позициями.

index = mylist.index(x, [start[,end]])

Параметр start не является обязательным. Если вы указываете значение для начала, то конец указывать необязательно.

Мы рассмотрим примеры, где подробно рассмотрим каждый из этих сценариев.

Нахождение индекса элемента в Python

Пример 1

В следующем примере мы взяли список с числами. С помощью метода index() найдем индекс пункта 8 в списке.

mylist = [21, 5, 8, 52, 21, 87]
item = 8

#search for the item
index = mylist.index(item)

print('The index of', item, 'in the list is:', index)

Вывод:

The index of 8 in the list is: 2

Элемент находится на 3-й позиции, поэтому функция mylist.index() вернула 2.

Пример 2

В следующем примере мы взяли список с числами. С помощью метода index() найдем индекс пункта 8 в списке, а также пропустим начало и конец. Функция рассматривает элементы в списке, начиная с начального индекса до конечной позиции в mylist.

mylist = [21, 8, 67, 52, 8, 21, 87]
item = 8
start=2
end=7

#search for the item
index = mylist.index(item, start, end)

print('The index of', item, 'in the list is:', index)

Вывод:

The index of 8 in the list is: 4

Объяснение:

mylist = [21, 8, 67, 52, 8, 21, 87]
                 ----------------- only this part of the list is considered
                         ^ index finds the element here
          0   1   2   3  4 => 4 is returned by index()

Пример 3: если элемент имеет несколько вхождений в списке

Список в Python может содержать несколько экземпляров элемента. В таких случаях возвращается только индекс первого появления указанного элемента в списке.

mylist = [21, 5, 8, 52, 21, 87, 52]
item = 52

#search for the item
index = mylist.index(item)

print('The index of', item, 'in the list is:', index)

Вывод:

The index of 52 in the list is: 3

Элемент 52 присутствует два раза, но метод index() возвращает только индекс первого вхождения.

Давайте разберемся, как работает index(). Функция просматривает список с самого начала. Когда элемент соответствует аргументу, функция возвращает этот индекс. Более поздние случаи игнорируются.

Пример 4: если элемент отсутствует

Если элемент, который мы ищем в списке, отсутствует, вы получите ValueError.

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

mylist = [21, 5, 8, 52, 21, 87, 52]
item = 67

#search for the item/element
index = mylist.index(item)

print('The index of', item, 'in the list is:', index)

Вывод:

Traceback (most recent call last):
  File "example.py", line 5, in <module>
    index = mylist.index(item)
ValueError: 67 is not in list

Поскольку index() может вызывать ValueError, используйте Try-Except. В следующем примере мы узнаем, как использовать инструкцию try-except для обработки этой ValueError.

mylist = [21, 5, 8, 52, 21, 87, 52]
item = 67

try:
	#search for the item
	index = mylist.index(item)
	print('The index of', item, 'in the list is:', index)
except ValueError:
	print('item not present')

Вывод:

item not present

Элемент, индекс которого мы пытаемся найти, отсутствует в списке. Следовательно, mylist.index (item) выдает ValueError, после блок перехватывает эту ошибку, и соответствующий блок выполняется.

Заключение

В этом руководстве по Python мы узнали, как найти индекс элемента в списке с помощью подробных примеров.

Добавить комментарий