2012-03-26 10 views
205

¿Cuál sería la forma más elegante y eficiente de encontrar/devolver el primer elemento de la lista que coincida con un determinado criterio?encontrar el primer elemento de secuencia que coincida con un criterio

Por ejemplo, si tengo una lista de objetos y me gustaría obtener el primer objeto de aquellos con el atributo obj.val==5. Por supuesto, podría usar la comprensión de la lista, pero incurriría en O (n) y si n es grande, es un desperdicio. También pude usar un ciclo con break una vez que se cumplió el criterio, pero pensé que podría haber una solución más pitónica/elegante.

+2

lo que si usted quiere conseguir el artículo y el índice? –

+1

@CharlieParker, para obtener tanto el índice como el elemento, use enumerate() - next ((idx, obj) para idx, obj en enumerate (objs) if obj.val == 5) –

Respuesta

367

Si no tiene otros índices o información ordenada para sus objetos, a continuación, tendrá que repetir hasta que se encuentre un objeto:

next(obj for obj in objs if obj.val==5) 

Ésta es sin embargo más rápido que una comprensión lista completa. Comparar estos dos:

[i for i in xrange(100000) if i == 1000][0] 

next(i for i in xrange(100000) if i == 1000) 

El primero necesita 5.75ms, el segundo 58.3μs (100 veces más rápido porque el bucle 100 veces más corto).

+93

'next' también proporciona' argumento default', en el caso de que no exista ningún objeto. P.ej. 'next ((i para i en el rango (500) si i> 600), 600)' devolverá 600. – Darthfett

+22

Python [** 'next()' **] (http://docs.python.org/2 /library/functions.html#next) –

+5

Bueno, esto es, pero esperaba que la respuesta correcta pareciera más fresca. Siempre publicitamos a Python por ser tan elegante. Si desea que sea robusto, debe proporcionar 'default' (por ejemplo' None') - y luego no debe olvidar que 'Generator expression debe estar entre paréntesis si no es solo argumento' ... Bueno, ¿cómo afecta esto a la legibilidad? ? P.ej. primer arugmento no de ruta: 'next ((arg para arg en sys.argv si no es os.path.exists (arg)), None)' - no muy amigable. –

2
a=[100,200,300,400,500] 
def search(b): 
try: 
    k=a.index(b) 
    return a[k] 
except ValueError: 
    return 'not found' 
print(search(500)) 

que va a devolver el objeto si se encuentra otra cosa que va a regresar "no encontrado"

+0

Esto es bueno, pero funciona solo cuando el criterio es una comparación con el elemento de la lista. Estaba buscando una solución más genérica para manejar un alcance más amplio de la selección – Jonathan

+0

pero @Jonathan en su pregunta mencionó ** forma eficiente de encontrar \ devolver el primer elemento de la lista ** por lo que la lista anterior a = [100,200,300,400,500] puede contener cualquier tipo de objeto, no solo números. –

+1

y concluyo la oración con "... que coincide con un cierto criterio", que no es lo mismo que con igualdad o identidad :) Hice +1 porque creo que su solución es buena para igualdad/identidad caso privado – Jonathan

Cuestiones relacionadas