¿Cómo encontrar todas las apariciones de un elemento en una lista?


378

index()solo dará la primera aparición de un elemento en una lista. ¿Hay un buen truco que devuelva todos los índices en una lista?


1
Estoy un poco confundido con esta pregunta: ¿desea buscar un elemento de forma recursiva en todos los niveles de una lista multidimensional, o solo desea buscar ocurrencias en el nivel superior de la lista?
Anderson Green

22
En mi opinión, debería haber un método de lista que haga exactamente esto.
otocan

Respuestas:


545

Puedes usar una lista de comprensión:

indices = [i for i, x in enumerate(my_list) if x == "whatever"]

3
En pitones anteriores, use filter () para esencialmente la misma funcionalidad.
Gleno

44
Las comprensiones de la lista aparecieron en python en 2.0, enumerateen 2.3. Entonces sí, si tu Python es antiguo, úsalo filter().
Steven Rumbalski

2
Esta técnica no encontrará todas las apariciones de un elemento en una matriz multidimensional. Por ejemplo, print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])devuelve en []lugar de [[0, 1], [0, 0], [1, 1]].
Anderson Green

10
@AndersonGreen: El término "matriz multidimensional" sugiere una estructura de datos que garantiza un tamaño uniforme a lo largo de cada uno de sus ejes. No existe tal estructura de datos en Python simple. Hay listas de listas, pero son muy diferentes de las "matrices multidimensionales". Si desea lo último, debería considerar usar NumPy, que le permite hacer cosas como (a == 1).nonzero()una matriz NumPy a.
Sven Marnach

2
@MadmanLee Si quieres algo rápido, usa NumPy. Ver la respuesta de JoshAdel
Georgy

117

Si bien no es una solución para las listas directamente, numpyrealmente brilla para este tipo de cosas:

import numpy as np
values = np.array([1,2,3,1,2,4,5,6,3,2,1])
searchval = 3
ii = np.where(values == searchval)[0]

devoluciones:

ii ==>array([2, 8])

Esto puede ser significativamente más rápido para listas (matrices) con una gran cantidad de elementos frente a algunas de las otras soluciones.


2
Noté que el [0] al final convierte lo que sería una matriz en una cadena. Tengo curiosidad por qué elegiste hacer esto.
amelia

55
@amelia [0]es necesaria porque wheredevuelve una tupla(array([2, 8], dtype=int64),)
Winand

1
Hola @Winand, puse [0] pero aún obtengo ambas partes. Aquí está mi código: (nrg.local_logs.all_id_resp_address es una lista) "ste =" 199.38.164.165 "value = np.where (nrg.local_logs.all_id_resp_address == ste) [0]" Seré feliz si puedes decirlo lo que hice mal
Tomer

2
@Tomer en primer lugar all_id_resp_addressdebería ser np.arrayno list.
Winand

1
@Tomer intentaste comparar listy str, obviamente, pasaste Falsea np.where. Cuando lo comparas np.arraycon algo. obtienes una matriz de valores booleanos. Luego np.whereencuentra posiciones de todos los Truevalores de esa matriz.
Winand

29

Una solución usando list.index:

def indices(lst, element):
    result = []
    offset = -1
    while True:
        try:
            offset = lst.index(element, offset+1)
        except ValueError:
            return result
        result.append(offset)

Es mucho más rápido que la comprensión de la lista enumerate, para listas grandes. También es mucho más lento que la numpysolución si ya tiene la matriz, de lo contrario, el costo de la conversión supera la ganancia de velocidad (probado en listas enteras con 100, 1000 y 10000 elementos).

NOTA: Una nota de precaución basada en el comentario de Chris_Rands: esta solución es más rápida que la comprensión de la lista si los resultados son lo suficientemente escasos, pero si la lista tiene muchas instancias del elemento que se está buscando (más del ~ 15% de la lista , en una prueba con una lista de 1000 enteros), la comprensión de la lista es más rápida.


3
Dices que esto es más rápido que una lista de compilación, ¿puedes mostrar tus tiempos que lo demuestren?
Chris_Rands

55
Esto fue hace mucho tiempo, probablemente lo usé timeit.timeitcon listas generadas aleatoriamente. Sin embargo, ese es un punto importante, y supongo que esa puede ser la razón por la que preguntas. En ese momento no se me ocurrió, pero las ganancias de velocidad solo son ciertas si los resultados son lo suficientemente escasos. Acabo de probar con una lista llena del elemento para buscar, y es mucho más lento que la comprensión de la lista.
Paulo Almeida el

18

Qué tal si:

In [1]: l=[1,2,3,4,3,2,5,6,7]

In [2]: [i for i,val in enumerate(l) if val==3]
Out[2]: [2, 4]

10
occurrences = lambda s, lst: (i for i,e in enumerate(lst) if e == s)
list(occurrences(1, [1,2,3,1])) # = [0, 3]

8

more_itertools.locate encuentra índices para todos los artículos que satisfacen una condición.

from more_itertools import locate


list(locate([0, 1, 1, 0, 1, 0, 0]))
# [1, 2, 4]

list(locate(['a', 'b', 'c', 'b'], lambda x: x == 'b'))
# [1, 3]

more_itertoolses una biblioteca de terceros > pip install more_itertools.


1
podría ser bueno si este lib se añadió a Conda-forja (aunque conda installse ha vuelto muy inestable en el rendimiento últimamente)
matanster

4

Una solución más (lo siento si hay duplicados) para todas las ocurrencias:

values = [1,2,3,1,2,4,5,6,3,2,1]
map(lambda val: (val, [i for i in xrange(len(values)) if values[i] == val]), values)

4

O use range(python 3):

l=[i for i in range(len(lst)) if lst[i]=='something...']

Para (pitón 2):

l=[i for i in xrange(len(lst)) if lst[i]=='something...']

Y luego (ambos casos):

print(l)

Es como se esperaba.


4

Usando filter () en python2.

>>> q = ['Yeehaw', 'Yeehaw', 'Googol', 'B9', 'Googol', 'NSM', 'B9', 'NSM', 'Dont Ask', 'Googol']
>>> filter(lambda i: q[i]=="Googol", range(len(q)))
[2, 4, 9]

2

Puedes crear un defaultdict

from collections import defaultdict
d1 = defaultdict(int)      # defaults to 0 values for keys
unq = set(lst1)              # lst1 = [1, 2, 2, 3, 4, 1, 2, 7]
for each in unq:
      d1[each] = lst1.count(each)
else:
      print(d1)

2

Obtener todas las ocurrencias 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 que nuestra función encuentre index

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]

Simple

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

Salida:

0
4

Esta respuesta fue la más fácil de implementar en mi código existente.
Ryan Harris

2

Usando un for-loop:

  • Las respuestas con enumeratey una comprensión de la lista son más eficientes y pitónicas, sin embargo, esta respuesta está dirigida a estudiantes a quienes no se les permite usar algunas de esas funciones integradas .
  • crear una lista vacía indices
  • crea el ciclo con for i in range(len(x)):, que esencialmente itera a través de una lista de ubicaciones de índice[0, 1, 2, 3, ..., len(x)-1]
  • en el bucle, agregue cualquiera i, donde x[i]es una coincidencia para value, paraindices
def get_indices(x: list, value: int) -> list:
    indices = list()
    for i in range(len(x)):
        if x[i] == value:
            indices.append(i)
    return indices

n = [1, 2, 3, -50, -60, 0, 6, 9, -60, -60]
print(get_indices(n, -60))

>>> [4, 8, 9]
  • Las funciones, get_indicesse implementan con sugerencias de tipo . En este caso, la lista, nes un grupo de ints, por lo tanto, buscamos value, también definido como un int.

Usando a while-loopy .index:

  • Con .index, use try-exceptpara el manejo de errores porque ValueErrorocurrirá si valueno está en la lista.
def get_indices(x: list, value: int) -> list:
    indices = list()
    i = 0
    while True:
        try:
            # find an occurrence of value and update i to that index
            i = x.index(value, i)
            # add i to the list
            indices.append(i)
            # advance i by 1
            i += 1
        except ValueError as e:
            break
    return indices

print(get_indices(n, -60))
>>> [4, 8, 9]

Su autodefinición get_indeiceses un poco más rápido (~ 15%) que la comprensión normal de la lista. Estoy tratando de resolverlo.
Travis

1

Si está utilizando Python 2, puede lograr la misma funcionalidad con esto:

f = lambda my_list, value:filter(lambda x: my_list[x] == value, range(len(my_list)))

¿Dónde my_listestá la lista de la que desea obtener los índices y valuees el valor buscado? Uso:

f(some_list, some_element)

1

Si necesita buscar todas las posiciones de los elementos entre ciertos índices , puede indicarlos:

[i for i,x in enumerate([1,2,3,2]) if x==2 & 2<= i <=3] # -> [3]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.