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?
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?
Respuestas:
Puedes usar una lista de comprensión:
indices = [i for i, x in enumerate(my_list) if x == "whatever"]
enumerate
en 2.3. Entonces sí, si tu Python es antiguo, úsalo filter()
.
print([i for i, x in enumerate([[1,1],[0,1]]) if x == 1])
devuelve en []
lugar de [[0, 1], [0, 0], [1, 1]]
.
(a == 1).nonzero()
una matriz NumPy a
.
Si bien no es una solución para las listas directamente, numpy
realmente 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.
[0]
es necesaria porque where
devuelve una tupla(array([2, 8], dtype=int64),)
all_id_resp_address
debería ser np.array
no list
.
list
y str
, obviamente, pasaste False
a np.where
. Cuando lo comparas np.array
con algo. obtienes una matriz de valores booleanos. Luego np.where
encuentra posiciones de todos los True
valores de esa matriz.
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 numpy
solució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.
timeit.timeit
con 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.
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_itertools
es una biblioteca de terceros > pip install more_itertools
.
conda install
se ha vuelto muy inestable en el rendimiento últimamente)
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)
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.
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]
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]
>>>
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]
for n, i in enumerate([1, 2, 3, 4, 1]):
if i == 1:
print(n)
Salida:
0
4
for-loop
:enumerate
y 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 .indices
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]
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]
get_indices
se implementan con sugerencias de tipo . En este caso, la lista, n
es un grupo de int
s, por lo tanto, buscamos value
, también definido como un int
.while-loop
y .index
:.index
, use try-except
para el manejo de errores porque ValueError
ocurrirá si value
no 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]
get_indeices
es un poco más rápido (~ 15%) que la comprensión normal de la lista. Estoy tratando de resolverlo.
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_list
está la lista de la que desea obtener los índices y value
es el valor buscado? Uso:
f(some_list, some_element)
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]