La pregunta es ambigua. ¿La respuesta es 2porque 0.9 > 0.7o porque 0.8 > 0.7? En otras palabras, ¿está buscando secuencialmente o en el orden de valores crecientes?
+1: aunque preferiría evitar los números mágicos: siguiente (idx para idx, valor en enumerar (L) si valor> 0,7)
truppo
38
+1 por simplicidad y next(), pero tal vez esto por legibilidad:next(i for i,v in enumerate(L) if v > 0.7)
Will Hardy
14
Si bien esto se ve bien, el caso en el que no haya resultado generará una StopIteration confusa.
Virgil Dupras
3
@Wim: Pero luego regresas a evaluar toda la secuencia. Úselo en itertools.chain()lugar de agregar listas como esta.
Ignacio Vazquez-Abrams
3
@Wim, no necesitas cadena () aquí. next () acepta el segundo argumento:next((i for i, x in enumerate(L) if x > value), -1)
jfs
35
si la lista está ordenada, entonces bisect.bisect_left(alist, value)es más rápido para una lista grande quenext(i for i, x in enumerate(alist) if x >= value) .
Buena respuesta: definitivamente fue de 5 a 6 veces más rápido para mí usando una pequeña lista ordenada de 4 elementos pero, (no estoy seguro si estoy cometiendo un error), pero cuando cronometro esto usando timeit con una larga lista de 10000 elementos numpy array Sin embargo, encuentro que es aproximadamente el doble de lento que la respuesta de comprensión de la lista anterior, lo que me sorprendió.
Adrian Tompkins
1
@AdrianTompkins: algo anda mal con su punto de referencia. bisect_leftes O (log n), mientras que listcomp es O (n), es decir, cuanto mayor sea, mayor será nla ventaja del bisect_left()lado. Intenté encontrar el índice de 500_000al range(10**6)usar bisect_left()-> 3.75 microsegundos y usar genexpr con next()-> 51.0 milisegundos [ 10_000veces] más lento como se esperaba.
El filtro @truppo en Python 3 devuelve un generador, por lo que no debería ser peor que una lista de comprensión. También encuentro esta forma más legible que la solución enumerada.
BubuIIC
Una cosa que no es agradable de este es que ingresa al manejo de excepciones si no hay ningún elemento en la secuencia mayor que .7.
Brian C.
La solución es técnicamente incorrecta. El autor de la pregunta preguntó cómo encontrar el índice del elemento en la lista. Pero esta solución devuelve un registro en su lugar. Eventmore en Python 3.8 es más lento que bisect_left()(el más rápido) y enumerate().
Sergey Nevmerzhitsky
16
>>> alist= [0.5, 0.3, 0.9, 0.8]
>>> [ n for n,i inenumerate(alist) if i>0.7 ][0]
2
fallará si 'x' es mayor que cualquier otro valor en la lista
mshsayem
2
@mshsayem: El problema está mal definido para este caso. El fracaso puede ser lo correcto.
S.Lott
@ S.Loot: Buen punto. En su defecto, si no en los resultados de lista en un error comprensible cuando se asigna esto a una variable: IndexError: list index out of range. El uso index = next[ n for n,i in enumerate(alist) if i>0.7 ]de error da: NameError: name 'index' is not defined. nextes ligeramente más rápido: la diferencia de tiempo es de 12,7 ns frente a 11,9 ns para 60 000 números.
Leo
11
for index, elem inenumerate(elements):
if elem > reference:
return index
raise ValueError("Nothing Found")
Tuve un problema similar cuando mi lista era muy larga. la comprensión o las soluciones basadas en filtros pasarían por la lista completa. itertools.take while romperá el ciclo una vez que la condición se vuelva falsa la primera vez:
from itertools import takewhile
deff(l, b):returnlen([x for x in takewhile(lambda x: x[1] <= b, enumerate(l))])
l = [0.5, 0.3, 0.9, 0.8]
f(l, 0.7)
¿por qué no escribe def f (l, b): return len (list (take while (lambda x: x [1] <= b, enumerate (l))))?
Avo Asatryan
2
Sé que ya hay muchas respuestas, pero a veces siento que la palabra pythonic se traduce en 'una sola línea'.
Cuando creo que una mejor definición está más cerca de esta respuesta :
"Aprovechar las características del lenguaje Python para producir código claro, conciso y fácil de mantener".
Si bien algunas de las respuestas anteriores son concisas, no las encuentro claras y un programador novato tardaría un tiempo en comprenderlas, por lo que no las hace extremadamente fáciles de mantener para un equipo formado por muchos niveles de habilidad.
l = [0.5, 0.3, 0.9, 0.8]
deff(l, x):for i in l:
if i >x: breakreturn l.index(i)
f(l,.7)
o
l = [0.5, 0.3, 0.9, 0.8]
deff(l, x):for i in l:
if i >x: return l.index(i)
f(l,.7)
Creo que lo anterior es fácil de entender por un novato y aún es lo suficientemente conciso como para ser aceptado por cualquier programador de Python veterano.
Eso se ve bastante hábil. Pero teóricamente recorrerá toda la lista y luego devolverá el primer resultado (mayor que x), ¿verdad? ¿Hay alguna forma de hacer uno que se detenga inmediatamente después de encontrar el primer resultado?
c00kiemonster
¿Qué hay de malo en recorrer la lista completa? si el primer valor mayor que 0,7 está cerca del final de la lista, no hay ninguna diferencia.
ghostdog74
3
Cierto. Pero en este caso particular, las listas en las que tengo la intención de usar la función son bastante largas, por lo que preferiría dejar de atravesar tan pronto como se encuentre una coincidencia ...
c00kiemonster
sea largo o no, si el primer valor es el último segundo elemento de la lista, ¡aún tendrá que recorrer toda la lista para llegar allí!
ghostdog74
4
@ ghostdog74: Sí, pero esta no es una razón para querer que todos los casos sean los peores casos.
UncleBens
0
También puede hacer esto usando numpy:
import numpy as np
list(np.array(SearchList) > x).index(True)
2
porque0.9 > 0.7
o porque0.8 > 0.7
? En otras palabras, ¿está buscando secuencialmente o en el orden de valores crecientes?Respuestas:
next(x[0] for x in enumerate(L) if x[1] > 0.7)
fuente
next()
, pero tal vez esto por legibilidad:next(i for i,v in enumerate(L) if v > 0.7)
itertools.chain()
lugar de agregar listas como esta.next((i for i, x in enumerate(L) if x > value), -1)
si la lista está ordenada, entonces
bisect.bisect_left(alist, value)
es más rápido para una lista grande quenext(i for i, x in enumerate(alist) if x >= value)
.fuente
bisect_left
es O (log n), mientras que listcomp es O (n), es decir, cuanto mayor sea, mayor serán
la ventaja delbisect_left()
lado. Intenté encontrar el índice de500_000
alrange(10**6)
usarbisect_left()
-> 3.75 microsegundos y usar genexpr connext()
-> 51.0 milisegundos [10_000
veces] más lento como se esperaba.filter(lambda x: x>.7, seq)[0]
fuente
bisect_left()
(el más rápido) yenumerate()
.>>> alist= [0.5, 0.3, 0.9, 0.8] >>> [ n for n,i in enumerate(alist) if i>0.7 ][0] 2
fuente
IndexError: list index out of range
. El usoindex = next[ n for n,i in enumerate(alist) if i>0.7 ]
de error da:NameError: name 'index' is not defined
.next
es ligeramente más rápido: la diferencia de tiempo es de 12,7 ns frente a 11,9 ns para 60 000 números.for index, elem in enumerate(elements): if elem > reference: return index raise ValueError("Nothing Found")
fuente
Otro:
map(lambda x: x>.7, seq).index(True)
fuente
1) NUMPY ARGWHERE, listas generales
Si está contento de usar numpy, lo siguiente funcionará en listas generales (ordenadas o sin clasificar):
numpy.argwhere(np.array(searchlist)>x)[0]
o si necesita la respuesta en forma de lista:
numpy.argwhere(np.array(searchlist)>x).tolist()[0]
o si necesita la respuesta como un índice entero:
numpy.argwhere(np.array(searchlist)>x).tolist()[0][0]
2) NUMPY BÚSQUEDA CLASIFICADA, listas ordenadas (muy eficiente para buscar listas)
Sin embargo, si su lista de búsqueda está ordenada, es mucho más limpio y agradable usar la función np.searchsorted :
Lo bueno de usar esta función es que además de buscar un único valor x, x también puede ser una lista, es decir, también puede devolver una lista de índices para una lista de valores buscados [x1, x2, x3 .. xn ], ( y es muy eficiente en relación con la comprensión de una lista en este caso ).
fuente
Tuve un problema similar cuando mi lista era muy larga. la comprensión o las soluciones basadas en filtros pasarían por la lista completa. itertools.take while romperá el ciclo una vez que la condición se vuelva falsa la primera vez:
from itertools import takewhile def f(l, b): return len([x for x in takewhile(lambda x: x[1] <= b, enumerate(l))]) l = [0.5, 0.3, 0.9, 0.8] f(l, 0.7)
fuente
Sé que ya hay muchas respuestas, pero a veces siento que la palabra pythonic se traduce en 'una sola línea'.
Cuando creo que una mejor definición está más cerca de esta respuesta :
"Aprovechar las características del lenguaje Python para producir código claro, conciso y fácil de mantener".
Si bien algunas de las respuestas anteriores son concisas, no las encuentro claras y un programador novato tardaría un tiempo en comprenderlas, por lo que no las hace extremadamente fáciles de mantener para un equipo formado por muchos niveles de habilidad.
l = [0.5, 0.3, 0.9, 0.8] def f(l, x): for i in l: if i >x: break return l.index(i) f(l,.7)
o
l = [0.5, 0.3, 0.9, 0.8] def f(l, x): for i in l: if i >x: return l.index(i) f(l,.7)
Creo que lo anterior es fácil de entender por un novato y aún es lo suficientemente conciso como para ser aceptado por cualquier programador de Python veterano.
Creo que escribir código tonto es positivo.
fuente
>>> f=lambda seq, m: [ii for ii in xrange(0, len(seq)) if seq[ii] > m][0] >>> f([.5, .3, .9, .8], 0.7) 2
fuente
También puede hacer esto usando
numpy
:import numpy as np list(np.array(SearchList) > x).index(True)
fuente
Prueba este:
def Renumerate(l): return [(len(l) - x, y) for x,y in enumerate(l)]
código de ejemplo:
Renumerate(range(10))
salida:
(10, 0) (9, 1) (8, 2) (7, 3) (6, 4) (5, 5) (4, 6) (3, 7) (2, 8) (1, 9)
fuente