Поиск индекса элемента по списку, содержащему его в Python - PullRequest
2683 голосов
/ 07 октября 2008

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

Ответы [ 28 ]

25 голосов
/ 22 августа 2017

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

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

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

21 голосов
/ 11 ноября 2015

Все индексы с функцией 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')
16 голосов
/ 08 августа 2017

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

С помощью 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
16 голосов
/ 29 мая 2013

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

>>> 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]
>>> 
15 голосов
/ 29 мая 2013

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

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

res = [[x[0] for x in a].index(y) for y in b]
13 голосов
/ 31 декабря 2014

А теперь, для чего-то совершенно другого ...

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

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 для разработки кода.

12 голосов
/ 28 марта 2014

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

10 голосов
/ 17 мая 2015

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

def find_element(p,t):
    i = 0
    for e in p:
        if e == t:
            return i
        else:
            i +=1
    return -1
5 голосов
/ 12 августа 2017

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

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

, где "стог сена" - это рассматриваемый список, а "игла" - это элемент для поиска.

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

5 голосов
/ 05 июля 2015
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)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...