una - recorrer lista python




Encontrar el índice de un elemento dado una lista que lo contiene en Python (18)

Encontrar el índice de un elemento dado una lista que lo contiene en Python

Para una lista ["foo", "bar", "baz"] y un elemento en la lista "bar" , ¿cuál es la forma más limpia de obtener su índice (1) en Python?

Bueno, seguro, está el método de índice, que devuelve el índice de la primera aparición:

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

Hay un par de problemas con este método:

  • Si el valor no está en la lista, obtendrás un ValueError
  • Si hay más de uno de los valores en la lista, solo obtendrá el índice del primero.

Sin valores

Si el valor puede faltar, debe capturar el ValueError .

Puedes hacerlo con una definición reutilizable como esta:

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

Y úsalo así:

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

Y la desventaja de esto es que probablemente tendrá una verificación de si el valor devuelto is o is not Ninguno:

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

Más de un valor en la lista.

Si pudiera tener más incidencias, no obtendrá información completa con list.index :

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

Podrías enumerar en una lista la comprensión de los índices:

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

Si no tiene incidencias, puede verificarlo con una verificación booleana del resultado, o simplemente no hacer nada si repite los resultados:

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

Mejores datos de munging con pandas.

Si tiene pandas, puede obtener fácilmente esta información con un objeto de la serie:

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

Una comprobación de comparación devolverá una serie de valores booleanos:

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

Pase esa serie de booleanos a la serie a través de la notación de subíndices, y obtendrá solo los miembros correspondientes:

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

Si solo desea los índices, el atributo de índice devuelve una serie de enteros:

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

Y si los quiere en una lista o tupla, simplemente páselos al constructor:

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

Sí, podría usar una lista de comprensión con enumeración también, pero eso no es tan elegante, en mi opinión, está haciendo pruebas de igualdad en Python, en lugar de dejar que el código incorporado escrito en C lo maneje:

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

¿Es este un problema XY ?

El problema XY está preguntando acerca de su intento de solución en lugar de su problema real.

¿Por qué crees que necesitas el índice dado un elemento en una lista?

Si ya conoce el valor, ¿por qué le importa dónde está en una lista?

Si el valor no está allí, capturar el ValueError es bastante detallado, y prefiero evitarlo.

Por lo general, estoy iterando sobre la lista, así que generalmente mantendré un puntero a cualquier información interesante, obteniendo el índice con enumerar.

Si está mezclando datos, probablemente debería usar pandas, que tiene herramientas mucho más elegantes que las soluciones de Python puras que he mostrado.

No recuerdo haber necesitado list.index , yo mismo. Sin embargo, he revisado la biblioteca estándar de Python y veo algunos usos excelentes para ella.

Hay muchos, muchos usos para ello en idlelib , para GUI y análisis de texto.

El módulo de keyword utiliza para encontrar marcadores de comentarios en el módulo para regenerar automáticamente la lista de palabras clave en él mediante metaprogramación.

En Lib / buzon.py parece estar usándolo como una asignación ordenada:

key_list[key_list.index(old)] = new

y

del key_list[key_list.index(key)]

En Lib / http / cookiejar.py, parece ser usado para obtener el próximo mes:

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

En Lib / tarfile.py similar a distutils para obtener una porción de un elemento:

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

En Lib / pickletools.py:

numtopop = before.index(markobject)

Lo que estos usos parecen tener en común es que parecen operar en listas de tamaños restringidos (importante debido al tiempo de búsqueda O (n) para list.index ), y se utilizan principalmente en el análisis (y la interfaz de usuario en el caso de Ocioso).

Si bien existen casos de uso para ello, son bastante infrecuentes. Si busca esta respuesta, pregúntese si lo que está haciendo es el uso más directo de las herramientas proporcionadas por el idioma para su caso de uso.

Para una lista ["foo", "bar", "baz"] y un elemento en la lista "bar" , ¿cómo obtengo su índice (1) en Python?


Si el desempeño es preocupante:

Se menciona en numerosas respuestas que el método list.index(item) del método list.index(item) es un algoritmo O (n). Está bien si necesita realizar esto una vez. Pero si necesita acceder a los índices de elementos varias veces, tiene más sentido crear primero un diccionario (O (n)) de pares de elementos de índice y luego acceder al índice en O (1) cada vez que lo necesite. eso.

Si está seguro de que los elementos de su lista nunca se repiten, puede:

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

# Create the dictionary
myDict = dict((e,i) for i,e in enumerate(myList))

# Lookup
myDict["bar"] # Returns 1
# myDict.get("blah") if you don't want an error to be raised if element not found.

Si puede tener elementos duplicados, y necesita devolver todos sus índices:

from collections import defaultdict as dd
myList = ["foo", "bar", "bar", "baz", "foo"]

# Create the dictionary
myDict = dd(list)
for i,e in enumerate(myList):
    myDict[e].append(i)

# Lookup
myDict["foo"] # Returns [0, 4]

Obtención de todas las apariciones y la posición de uno o más elementos (idénticos) en una lista

Con enumerate (alist) puede almacenar el primer elemento (n) que es el índice de la lista cuando el elemento x es igual a lo que busca.

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

Hagamos nuestra función de encontrar índice.

Esta función toma el elemento y la lista como argumentos y devuelve la posición del elemento en la lista, como vimos antes.

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

Salida

[1, 3, 5, 7]

Sencillo

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

Salida:

0
4

Como las listas de Python están basadas en cero, podemos usar la función incorporada de zip de la siguiente manera:

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

donde "pajar" es la lista en cuestión y "aguja" es el ítem a buscar.

(Nota: aquí estamos iterando usando i para obtener los índices, pero si necesitamos centrarnos en los elementos, podemos cambiar a j).


El método de index() Python index() emite un error si no se encontró el elemento, lo que apesta.

Entonces, en lugar de eso, puede hacerlo similar a la función indexOf() de JavaScript que devuelve -1 si no se encontró el elemento:

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

Encontrando el índice del artículo x en la lista L :

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

Hay dos posibilidades si la lista no tiene elementos repetidos que necesita para verificar el índice

 eg: li=[10,20,30] # here need to get index of 20 means
     li.index(20) # will work properly because 20 is not repeated

Si es repetido significa que solo te dará el primer índice.

Si necesita obtener todo el índice donde está presente el artículo significa

eg: li=[10,20,30,20,40, 50, 10] # here need to get index of 20 means its have 2 index (1,3) 

para conseguir eso necesitas hacerlo como

 li=[10,20,30,20,40, 50, 10]
 [i for i, e in enumerate(li) if e == 20]

entonces obtendrás una lista de índice como o / p like [1,3]


Hay una respuesta más funcional a esto.

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

Forma más genérica:

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

Otra opción

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

Para aquellos que vienen de otro idioma como yo, tal vez con un simple bucle sea más fácil de entender y usar:

mylist = ["foo", "bar", "baz", "bar"]
newlist = enumerate(mylist)
for index, item in newlist:
  if item == "bar":
    print(index, item)

Estoy agradecido por Entonces, ¿qué hace exactamente enumerar? . Eso me ayudó a entender.


Según lo indicado por @TerryA, muchas respuestas discuten cómo encontrar un índice.

more_itertools es una biblioteca de terceros con herramientas para localizar múltiples índices dentro de un iterable.

Dado

import more_itertools as mit


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

Código

Encontrar índices de observaciones múltiples:

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

Prueba varios artículos:

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

Ver también más opciones con more_itertools.locate . Instalar via more_itertools .


Si desea todos los índices, puede usar 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),)

Es una solución clara, legible.


Surgirá un problema si el elemento no está en la lista. Esta función maneja el problema:

# 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

Todas las funciones propuestas aquí reproducen el comportamiento inherente del lenguaje pero ocultan lo que está sucediendo.

[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

¿Por qué escribir una función con manejo de excepciones si el lenguaje proporciona los métodos para hacer lo que usted desea?


Una cosa que es realmente útil para aprender Python es usar la función de ayuda interactiva:

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

class list(object)
 ...

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

que a menudo te llevará al método que estás buscando.


Una variante en la respuesta de FMc y user7177 dará un dictado que puede devolver todos los índices para cualquier entrada:

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

También puede usar esto como un trazador de líneas para obtener todos los índices para una sola entrada. No hay garantías de eficiencia, aunque sí utilicé set (a) para reducir el número de veces que se llama a la lambda.


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

Referencia: Estructuras de datos> Más en listas

Advertencias siguen

Tenga en cuenta que si bien esta es quizás la forma más limpia de responder la pregunta, el index es un componente bastante débil de la list API, y no puedo recordar la última vez que lo usé enojado. Se me indicó en los comentarios que, debido a que esta respuesta está muy referida, debería ser más completa. Algunas advertencias sobre list.index siguen. Es probable que inicialmente valga la pena echarle un vistazo al docstring para ello:

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

Tiempo-complejidad lineal en longitud de lista

Una llamada de index verifica todos los elementos de la lista en orden, hasta que encuentra una coincidencia. Si su lista es larga y no sabe aproximadamente en qué lugar de la lista aparece, esta búsqueda podría convertirse en un cuello de botella. En ese caso, debe considerar una estructura de datos diferente. Tenga en cuenta que si sabe aproximadamente dónde encontrar la coincidencia, puede dar una pista al index . Por ejemplo, en este fragmento, l.index(999_999, 999_990, 1_000_000) es aproximadamente cinco órdenes de magnitud más rápido que l.index(999_999) directo l.index(999_999) , porque el primero solo tiene que buscar 10 entradas, mientras que el último busca un millón:

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

Solo devuelve el índice de la primera coincidencia a su argumento.

Una llamada para index busca en la lista en orden hasta que encuentra una coincidencia y se detiene allí. Si espera necesitar índices de más coincidencias, debe usar una lista de comprensión o expresión de generador.

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

La mayoría de los lugares en los que alguna vez habría usado el index , ahora uso una comprensión de lista o una expresión generadora porque son más generalizables. Entonces, si está considerando alcanzar el index , eche un vistazo a estas excelentes características de Python.

Lanza si el elemento no está presente en la lista.

Una llamada para index da como resultado un ValueError si el elemento no está presente.

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

Si el elemento puede no estar presente en la lista, debería

  1. Verifíquelo primero con el item in my_list (enfoque limpio y legible), o
  2. Envuelva la llamada de index en un bloque try/except que atrapa ValueError (probablemente más rápido, al menos cuando la lista de búsqueda es larga, y el elemento generalmente está presente).

a = ["foo","bar","baz",'bar','any','much']

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






list