2012-03-26 10 views
205

Quale sarebbe il modo più elegante ed efficiente per trovare/restituire la prima voce dell'elenco che corrisponde a un determinato criterio?trova la prima sequenza che corrisponde a un criterio

Ad esempio, se ho un elenco di oggetti e vorrei ottenere il primo oggetto di quelli con attributo obj.val==5. Naturalmente potrei usare la comprensione delle liste, ma ciò dovrebbe comportare O (n) e se n è grande, è uno spreco. Potrei anche usare un ciclo con break una volta che il criterio è stato rispettato, ma ho pensato che ci potrebbe essere una soluzione più pitone/elegante.

+2

cosa succede se si vuole ottenere l'oggetto e l'indice? –

+1

@CharlieParker, per ottenere sia l'indice che l'elemento, utilizzare enumerate() - next ((idx, obj) per idx, obj in enumerate (objs) if obj.val == 5) –

risposta

367

Se non si dispone di altri indici o le informazioni ordinate per gli oggetti, quindi si dovrà scorrere fino a quando viene trovato un tale oggetto:

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

Questo è comunque più veloce di una lista completa comprensione. Confronta questi due:

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

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

La prima si ha la necessità 5.75ms, la seconda 58.3μs (100 volte più veloce perché il ciclo 100 volte più breve).

+93

'next' fornisce anche un' argomento predefinito', nel caso in cui non esista alcun oggetto. Per esempio. 'next ((i for i in range (500) if i> 600), 600)' restituirà 600. – Darthfett

+22

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

+5

Beh, questo è tutto, ma mi aspettavo solo che la risposta giusta apparisse più interessante. Pubblichiamo sempre python per essere così eleganti. Se vuoi che sia robusto, dovresti fornire 'default' (es.' None') - e quindi non devi dimenticare che 'L'espressione del generatore deve essere parentesi se non solo l'argomento '... Beh, come influisce sulla leggibilità? ? Per esempio. primo arugmento non-path: 'next ((arg per arg in sys.argv se non os.path.exists (arg)), None)' - non molto amichevole. –

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

che restituisca l'oggetto se trovato altrimenti tornerà "non trovato"

+0

Questo è bello, ma funziona solo quando il criterio è un confronto per la voce dell'elenco. Stavo cercando una soluzione più generica per gestire un più ampio ambito di selezione – Jonathan

+0

ma @Jonathan nella tua domanda hai menzionato ** modo efficiente di trovare \ restituire il primo elemento della lista ** così l'elenco sopra a = [100,200,300,400,500] può contenere qualsiasi tipo di oggetto non solo numeri. –

+1

e concludo la frase con "... che corrisponde a un determinato criterio", che non è la stessa di corrispondere su uguaglianza o identità :) Ho fatto +1 perché penso che la soluzione sia valida per l'uguaglianza \ caso privato di identità – Jonathan

Problemi correlati