Поиск индекса элемента по списку, содержащему его в Python

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

48 ответов

Решение
>>> ["foo", "bar", "baz"].index("bar")
1

Справка: Структуры данных> Подробнее о списках

Предостережения следуют

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

>>> print(list.index.__doc__)
L.index(value, [start, [stop]]) -> integer -- return first index of value.
Raises ValueError if the value is not present.

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

index call проверяет каждый элемент списка по порядку, пока не найдет совпадение. Если ваш список длинный и вы не знаете, где именно он находится, этот поиск может стать узким местом. В этом случае вы должны рассмотреть другую структуру данных. Обратите внимание, что если вы точно знаете, где найти соответствие, вы можете дать index Намек. Например, в этом фрагменте, l.index(999_999, 999_990, 1_000_000) примерно на пять порядков быстрее, чем прямой l.index(999_999)потому что первый должен искать только 10 записей, а второй ищет миллион:

>>> 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

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

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

>>> [1, 1].index(1)
0
>>> [i for i, e in enumerate([1, 2, 1]) if e == 1]
[0, 2]
>>> g = (i for i, e in enumerate([1, 2, 1]) if e == 1)
>>> next(g)
0
>>> next(g)
2

Большинство мест, где я когда-то использовал indexЯ теперь использую списочное понимание или генераторное выражение, потому что они более обобщаемы. Так что, если вы планируете достичь indexвзгляните на эти отличные возможности Python.

Выдает, если элемент отсутствует в списке

Вызов index приводит к ValueError если предмета нет.

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

Если элемент может отсутствовать в списке, вы должны либо

  1. Проверьте это сначала с item in my_list (чистый, читаемый подход) или
  2. Обернуть index позвонить в try/except блок который ловит ValueError (вероятно, быстрее, по крайней мере, когда список для поиска длинный, а элемент обычно присутствует.)

Одна вещь, которая действительно полезна при изучении Python - это использовать функцию интерактивной справки:

>>> help(["foo", "bar", "baz"])
Help on list object:

class list(object)
 ...

 |
 |  index(...)
 |      L.index(value, [start, [stop]]) -> integer -- return first index of value
 |

который часто приведет вас к методу, который вы ищете.

Большинство ответов объясняют, как найти один индекс, но их методы не возвращают несколько индексов, если элемент находится в списке несколько раз. использование 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() (это почти такой же подход, как перечислять):

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

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

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

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

| индекс(...)
| L.index (value, [start, [stop]]) -> integer - вернуть первый индекс значения

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"])
a = ["foo","bar","baz",'bar','any','much']

indexes = [index for index in range(len(a)) if a[index] == 'bar']

Проблема возникнет, если элемент отсутствует в списке. Эта функция обрабатывает проблему:

# if element is found it returns index of element else returns None

def find_element_in_list(element, list_element):
    try:
        index_element = list_element.index(element)
        return index_element
    except ValueError:
        return None

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

if 'your_element' in mylist:
    print mylist.index('your_element')
else:
    print None

Если вы хотите все индексы, то вы можете использовать NumPy:

import numpy as np

array = [1, 2, 1, 3, 4, 5, 1]
item = 1
np_array = np.array(array)
item_index = np.where(np_array==item)
print item_index
# Out: (array([0, 2, 6], dtype=int64),)

Это понятное, читаемое решение.

Поиск индекса элемента по списку, содержащему его в Python

Для списка ["foo", "bar", "baz"] и элемент в списке "bar"Какой самый чистый способ получить свой индекс (1) в Python?

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

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

Есть несколько проблем с этим методом:

  • если значение отсутствует в списке, вы получите ValueError
  • если в списке более одного значения, вы получите индекс только для первого

Нет значений

Если значение может отсутствовать, вам нужно поймать ValueError,

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

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

И используйте это так:

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

И недостатком этого является то, что у вас, вероятно, будет проверка, если возвращаемое значение is или же is not Никто:

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

Более одного значения в списке

Если бы вы могли иметь больше случаев, вы не получите полную информацию с list.index:

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

Вы можете перечислить в список, понимающий индексы:

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

Если у вас нет вхождений, вы можете проверить это с помощью логической проверки результата или просто ничего не делать, если вы просматриваете результаты:

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

Лучшее копание данных с пандами

Если у вас есть панды, вы можете легко получить эту информацию с помощью объекта Series:

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

Проверка сравнения вернет серию логических значений:

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

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

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

Если вам нужны только индексы, атрибут index возвращает последовательность целых чисел:

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

И если вы хотите, чтобы они были в списке или кортеже, просто передайте их конструктору:

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

Да, вы могли бы использовать списочное понимание и с enumerate, но, на мой взгляд, это не так элегантно - вы выполняете тесты на равенство в Python вместо того, чтобы позволить встроенному коду, написанному на C, обрабатывать его:

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

Это проблема XY?

Проблема XY спрашивает о вашей попытке решения, а не о вашей реальной проблеме.

Как вы думаете, почему вам нужен индекс, заданный элементом в списке?

Если вы уже знаете значение, почему вас волнует, где оно находится в списке?

Если значение не там, ловя ValueError довольно многословно - и я предпочитаю избегать этого.

В любом случае я обычно перебираю список, поэтому я обычно держу указатель на любую интересную информацию, получая индекс с перечислением.

Если вы манипулируете данными, вам, вероятно, следует использовать панд - у которых гораздо более изящные инструменты, чем чисто обходные пути Python, которые я показал.

Я не припомню нуждаюсь list.index, себя. Тем не менее, я просмотрел стандартную библиотеку Python и вижу некоторые отличные варианты ее использования.

Есть много, много применений для этого в idlelib, для GUI и разбора текста.

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

В lib/mailbox.py кажется, что он используется как упорядоченное отображение:

key_list[key_list.index(old)] = new

а также

del key_list[key_list.index(key)]

В Lib/http/cookiejar.py, похоже, используется для получения следующего месяца:

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

В lib/tarfile.py аналогично distutils для получения среза до элемента:

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

В Lib/pickletools.py:

numtopop = before.index(markobject)

Похоже, что эти обычаи объединяют то, что они работают со списками ограниченных размеров (важно из-за времени поиска O(n) для list.index), и они в основном используются при разборе (и пользовательский интерфейс в случае простоя).

Хотя для этого есть варианты использования, они довольно редки. Если вы обнаружите, что ищете этот ответ, спросите себя, является ли то, что вы делаете, наиболее прямым использованием инструментов, предоставляемых языком для вашего варианта использования.

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

[i for i in range(len(mylist)) if mylist[i]==myterm]  # get the indices

[each for each in mylist if each==myterm]             # get the items

mylist.index(myterm) if myterm in mylist else None    # get the first index and fail quietly

Зачем писать функцию с обработкой исключений, если язык предоставляет методы для того, что вы сами хотите?

Получение всех вхождений и положения одного или нескольких (идентичных) элементов в списке

С помощью enumerate(alist) вы можете сохранить первый элемент (n), который является индексом списка, когда элемент x равен тому, что вы ищете.

>>> alist = ['foo', 'spam', 'egg', 'foo']
>>> foo_indexes = [n for n,x in enumerate(alist) if x=='foo']
>>> foo_indexes
[0, 3]
>>>

Давайте сделаем нашу функцию findindex

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

def indexlist(item2find, list_or_string):
  "Returns all indexes of an item in a list or a string"
  return [n for n,item in enumerate(list_or_string) if item==item2find]

print(indexlist("1", "010101010"))

Выход


[1, 3, 5, 7]

просто

for n, i in enumerate([1, 2, 3, 4, 1]):
    if i == 1:
        print(n)

Выход:

0
4
      me = ["foo", "bar", "baz"]
me.index("bar") 

Вы можете применить это для любого члена списка, чтобы получить их индекс

Все индексы с zip функция:

get_indexes = lambda x, xs: [i for (y, i) in zip(xs, range(len(xs))) if x == y]

print get_indexes(2, [1, 2, 3, 4, 5, 6, 3, 2, 3, 2])
print get_indexes('f', 'xsfhhttytffsafweef')

Просто вы можете пойти с

a = [['hand', 'head'], ['phone', 'wallet'], ['lost', 'stock']]
b = ['phone', 'lost']

res = [[x[0] for x in a].index(y) for y in b]

Другой вариант

>>> a = ['red', 'blue', 'green', 'red']
>>> b = 'red'
>>> offset = 0;
>>> indices = list()
>>> for i in range(a.count(b)):
...     indices.append(a.index(b,offset))
...     offset = indices[-1]+1
... 
>>> indices
[0, 3]
>>> 

А сейчас нечто соверешнно другое...

... как подтверждение существования элемента до получения индекса. Приятной особенностью этого подхода является то, что функция всегда возвращает список индексов, даже если это пустой список. Он также работает со строками.

def indices(l, val):
    """Always returns a list containing the indices of val in the_list"""
    retval = []
    last = 0
    while val in l[last:]:
            i = l[last:].index(val)
            retval.append(last + i)
            last += i + 1   
    return retval

l = ['bar','foo','bar','baz','bar','bar']
q = 'bar'
print indices(l,q)
print indices(l,'bat')
print indices('abcdaababb','a')

Когда вставлено в интерактивное окно Python:

Python 2.7.6 (v2.7.6:3a1db0d2747e, Nov 10 2013, 00:42:54) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def indices(the_list, val):
...     """Always returns a list containing the indices of val in the_list"""
...     retval = []
...     last = 0
...     while val in the_list[last:]:
...             i = the_list[last:].index(val)
...             retval.append(last + i)
...             last += i + 1   
...     return retval
... 
>>> l = ['bar','foo','bar','baz','bar','bar']
>>> q = 'bar'
>>> print indices(l,q)
[0, 2, 4, 5]
>>> print indices(l,'bat')
[]
>>> print indices('abcdaababb','a')
[0, 4, 5, 7]
>>> 

Обновить

После еще одного года бездумной разработки Python я немного смутился из-за своего первоначального ответа, поэтому, чтобы исправить ситуацию, можно, конечно, использовать приведенный выше код; тем не менее, гораздо более идиоматический способ получить такое же поведение - использовать понимание списка вместе с функцией enumerate().

Что-то вроде этого:

def indices(l, val):
    """Always returns a list containing the indices of val in the_list"""
    return [index for index, value in enumerate(l) if value == val]

l = ['bar','foo','bar','baz','bar','bar']
q = 'bar'
print indices(l,q)
print indices(l,'bat')
print indices('abcdaababb','a')

Который при вставке в интерактивное окно Python дает:

Python 2.7.14 |Anaconda, Inc.| (default, Dec  7 2017, 11:07:58) 
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def indices(l, val):
...     """Always returns a list containing the indices of val in the_list"""
...     return [index for index, value in enumerate(l) if value == val]
... 
>>> l = ['bar','foo','bar','baz','bar','bar']
>>> q = 'bar'
>>> print indices(l,q)
[0, 2, 4, 5]
>>> print indices(l,'bat')
[]
>>> print indices('abcdaababb','a')
[0, 4, 5, 7]
>>> 

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

Если приведенная выше строка кода по-прежнему не имеет смысла для вас, я настоятельно рекомендую вам "понимание списков Python" в Google и потратьте несколько минут на ознакомление. Это всего лишь одна из многих мощных функций, которые позволяют использовать Python для разработки кода.

Друг мой, я сделал самый простой код для решения твоего вопроса. Пока вы получали гигантские строки кодов, я здесь, чтобы предоставить вам двухстрочный код, который все благодаря помощи index()функция в питоне.

      LIST = ['foo' ,'boo', 'shoo']
print(LIST.index('boo'))

Выход:

      1

Надеюсь, я дал вам лучший и самый простой ответ, который может вам очень помочь.

Вариант ответа от FMc и user7177 даст указание, которое может вернуть все индексы для любой записи:

>>> a = ['foo','bar','baz','bar','any', 'foo', 'much']
>>> l = dict(zip(set(a), map(lambda y: [i for i,z in enumerate(a) if z is y ], set(a))))
>>> l['foo']
[0, 5]
>>> l ['much']
[6]
>>> l
{'baz': [2], 'foo': [0, 5], 'bar': [1, 3], 'any': [4], 'much': [6]}
>>> 

Вы также можете использовать это как один вкладыш, чтобы получить все индексы для одной записи. Нет никаких гарантий эффективности, хотя я использовал set (a), чтобы уменьшить количество вызовов лямбды.

Нахождение индекса элемента x в списке L:

idx = L.index(x) if (x in L) else -1

Это решение не так мощно, как другие, но если вы новичок и знаете только о forЦиклы все еще возможно найти первый индекс элемента, избегая ValueError:

def find_element(p,t):
    i = 0
    for e in p:
        if e == t:
            return i
        else:
            i +=1
    return -1

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

      a_list = ["a", "b", "a"]
print([index for (index , item) in enumerate(a_list) if item == "a"])

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

list =  ["foo", "bar", "baz"]

item_to_find = "foo"

if item_to_find in list:
      index = list.index(item_to_find)
      print("Index of the item is " + str(index))
else:
    print("That word does not exist") 

Питон index() Метод выдает ошибку, если элемент не был найден, что отстой!

Таким образом, вместо этого вы можете сделать его похожим на indexOf() функция JavaScript, которая возвращает -1 если предмет не был найден:

    try:
        index = array.index('search_keyword')
    except ValueError:
        index = -1

Он просто использует функцию Python array.index() и с помощью простого Try / Except он возвращает позицию записи, если она найдена в списке, и возвращает -1, если она не найдена в списке (например, в JavaScript с функцией indexOf()).

      fruits = ['apple', 'banana', 'cherry']

try:
  pos = fruits.index("mango")
except:
  pos = -1

В этом случае «манго» в списке нет. fruits поэтому переменная равна -1, если бы я искал "вишня", pos переменная будет 2.

Есть более функциональный ответ на это.

list(filter(lambda x: x[1]=="bar",enumerate(["foo", "bar", "baz", "bar", "baz", "bar", "a", "b", "c"])))

Более общая форма:

def get_index_of(lst, element):
    return list(map(lambda x: x[0],\
       (list(filter(lambda x: x[1]==element, enumerate(lst))))))

Если вам нужен только один, этот хорошо читается...

some_list = ['list', 'of', 'something you like']

# StopIteration is raised if it doesn't find
index_of_value_you_like = next(
    i 
    for i, value in enumerate(some_list)
    if value == 'something you like')

... но для всех индексов тогда...

all_values_that_match_your_criteria = [
    i
    for i, instance in enumerate(some_list_of_classes)
    if instance.matches_your_criteria()]

name ="bar"
list = [["foo", 1], ["bar", 2], ["baz", 3]]
new_list=[]
for item in list:
    new_list.append(item[0])
print(new_list)
try:
    location= new_list.index(name)
except:
    location=-1
print (location)

Это учитывает, если строки нет в списке, если ее нет в списке, то location = -1

Если вы собираетесь найти индекс один раз, то можно использовать метод "index". Однако, если вы собираетесь искать данные более одного раза, я рекомендую использовать модуль bisect. Имейте в виду, что при использовании модуля пополам данные должны быть отсортированы. Итак, вы сортируете данные один раз, а затем можете использовать разделение пополам. Использование модуля bisect на моем компьютере примерно в 20 раз быстрее, чем использование метода индекса.

Вот пример кода с использованием синтаксиса Python 3.8 и выше:

import bisect
from timeit import timeit

def bisect_search(container, value):
    return (
      index 
      if (index := bisect.bisect_left(container, value)) < len(container) 
      and container[index] == value else -1
    )

data = list(range(1000))
# value to search
value = 666

# times to test
ttt = 1000

t1 = timeit(lambda: data.index(value), number=ttt)
t2 = timeit(lambda: bisect_search(data, value), number=ttt)

print(f"{t1=:.4f}, {t2=:.4f}, diffs {t1/t2=:.2f}")

Выход:

t1=0.0400, t2=0.0020, diffs t1/t2=19.60

Я считаю, что эти два решения лучше, и я попробовал их сам

      >>> expences = [2200, 2350, 2600, 2130, 2190]
>>> 2000 in expences
False
>>> expences.index(2200)
0
>>> expences.index(2350)
1
>>> index = expences.index(2350)
>>> expences[index]
2350

>>> try:
...     print(expences.index(2100))
... except ValueError as e:
...     print(e)
... 
2100 is not in list
>>> 


Другие вопросы по тегам