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

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

Ответов (25)

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

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

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

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

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

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

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

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

An index call checks every element of the list in order, until it finds a match. If your list is long, and you don't know roughly where in the list it occurs, this search could become a bottleneck. In that case, you should consider a different data structure. Note that if you know roughly where to find the match, you can give index a hint. For instance, in this snippet, l.index(999_999, 999_990, 1_000_000) is roughly five orders of magnitude faster than straight l.index(999_999), because the former only has to search 10 entries, while the latter searches a million:

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

Only returns the index of the first match to its argument

Вызов функции 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(возможно, быстрее, по крайней мере, когда список для поиска длинный и элемент обычно присутствует).

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

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

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

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

# 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

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

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

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

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

Вариант ответа от 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), чтобы уменьшить количество вызовов лямбда.

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

if 'your_element' in mylist:
    print mylist.index('your_element')
else:
    print None
a = ["foo","bar","baz",'bar','any','much']

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

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

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

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 предложил в своем предыдущем ответе . В то время, когда я первоначально ответил на этот вопрос, я даже не видел этого ответа, потому что я его не понимал. Надеюсь, что мой несколько более подробный пример поможет понять.

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

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

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

Все индексы с 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')

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

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

Ну, конечно, есть метод 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 None:

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 довольно многословно - и я предпочитаю этого избегать.

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

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

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

У него есть много, много применений в idlelib графическом интерфейсе и текстовом синтаксическом анализе.

В 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 ), и они в основном используются при синтаксическом анализе (и пользовательском интерфейсе в случае простоя).

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

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

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

Как указывает @TerryA, во многих ответах обсуждается, как найти один индекс.

more_itertools- это сторонняя библиотека с инструментами для поиска нескольких индексов в итерируемом объекте.

Данный

import more_itertools as mit


iterable = ["foo", "bar", "baz", "ham", "foo", "bar", "baz"]

Код

Найдите индексы нескольких наблюдений:

list(mit.locate(iterable, lambda x: x == "bar"))
# [1, 5]

Протестируйте несколько предметов:

list(mit.locate(iterable, lambda x: x in {"bar", "ham"}))
# [1, 3, 5]

Смотрите также другие варианты с more_itertools.locate. Установить через > pip install more_itertools.

Если вам нужны все индексы, вы можете использовать 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),)

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

Простой вариант:

a = ["foo", "bar", "baz"]
[i for i in range(len(a)) if a[i].find("bar") != -1]

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

С помощью 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

Поскольку списки Python начинаются с нуля, мы можем использовать встроенную функцию zip следующим образом:

>>> [i for i,j in zip(range(len(haystack)), haystack) if j == 'needle' ]

где «стог сена» - это список, о котором идет речь, а «игла» - это предмет, который нужно искать.

(Примечание: здесь мы повторяем, используя i, чтобы получить индексы, но если нам нужно сосредоточиться на элементах, мы можем переключиться на j.)

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

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

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

from collections import defaultdict

index_dict = defaultdict(list)    
word_list =  ['foo','bar','baz','bar','any', 'foo', 'much']

for word_index in range(len(word_list)) :
    index_dict[word_list[word_index]].append(word_index)

word_index_to_find = 'foo'       
print(index_dict[word_index_to_find])

# output :  [0, 5]

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

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

class list(object)
 ...

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

что часто приводит вас к искомому методу.

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"])

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

[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

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

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