2015-08-01 9 views
7

Sto sviluppando un programma Python per rilevare i nomi delle città in un elenco di record. Il codice che ho sviluppato fino ad ora è la seguente:Come posso sapere quale elemento di una lista ha attivato una funzione any()?

aCities = ['MELBOURNE', 'SYDNEY', 'PERTH', 'DUBAI', 'LONDON'] 

cxTrx = db.cursor() 
cxTrx.execute('SELECT desc FROM AccountingRecords') 

for row in cxTrx.fetchall() : 
    if any(city in row[0] for city in aCities) : 
     #print the name of the city that fired the any() function 
    else : 
     # no city name found in the accounting record 

Il codice funziona bene per rilevare quando una città nella lista dei aCities' si trova nel record di contabilità, ma come qualsiasi funzione() restituisce solo Vero o Falso Faccio fatica a sapere quale città (Melbourne, Sydney, Perth, Dubai o Londra) ha attivato l'uscita.

Ho provato con aCities.index e in coda, ma finora non ha avuto successo.

risposta

10

Non penso sia possibile con any. È possibile utilizzare next con valore di default:

for row in cxTrx.fetchall() : 
    city = next((city for city in aCities if city in row[0]), None) 
    if city is not None: 
     #print the name of the city that fired the any() function 
    else : 
     # no city name found in the accounting record 
4

Non si perché any restituisce solo un valore booleano. Ma è possibile utilizzare next:

city = next((city for city in aCities if city in row[0]), None) 
if city: 
    ... 

Con questa sintassi troverete il primo city che è una sottostringa della descrizione memorizzata nella riga di database. Se non ce n'è uno, il secondo parametro, ad es. Nessuno, sarà restituito.

+0

Grazie @JuniorCompressor! –

3

No, è possibile con any. E 'un po' di una bravata - è "legge divertente" - ma funziona:

if any(city in row[0] and not print(city) for city in aCities): 
    # city in row[0] found, and already printed :) 
    # do whatever else you might want to do 
else: 
    # no city name found in the accounting record 

o più conciso, se tutto quello che vuole veramente fare è stampare la città:

if not any(city in row[0] and not print(city) for city in aCities): 
    # no city name found in the accounting record 

Funziona per tre motivi:

  1. any fermate al primo vero elemento (truthy),
  2. and è corto circuito, così sarà not print(city) essere corretto solo se city in row[0] è vero e
  3. print restituisce None, quindi not print(...) è sempre True.

PS: Come @falsetru sottolinea, in Python 2.x print non è una funzione, quindi dovrete dire prima:

from __future__ import print_function 

Come ho già detto, funziona per 3 ragioni - Python 3 motivi;) Oh, aspetta - che è di 4 motivi ...

+0

Clever, ma 'print' in Python 2.x è un'istruzione, non una funzione. Faresti meglio a menzionare 'da __future__ import print_function'. +1 – falsetru

1

per completezza, ecco una soluzione con uno standard per-loop:

for city in aCities: 
    if city in row[0]: 
     print 'Found city', city 
     break 
else: 
    print 'Did not find any city' 

Questo dovrebbe avere lo stesso comportamento di cortocircuito di any, poiché si interrompe dal ciclo for quando la condizione è soddisfatta. La parte else viene eseguita quando il ciclo for viene eseguito fino alla fine senza interruzione, vedere this question.

Anche se questa soluzione utilizza più linee, in realtà utilizza meno caratteri rispetto alle altre soluzioni, poiché non v'è alcuna chiamata per next(..., None), non ha il city = assegnazione in più e non c'è secondo if city is None (al costo di uno in più break). Quando le cose si complicano, a volte è più chiaro scrivere esplicitamente il ciclo for, quindi unire insieme alcune espressioni del generatore e le dichiarazioni next.

+0

Grazie @ bas-swinckels. Il codice dovrebbe elaborare circa 10 milioni di record e l'elenco delle città sarà di circa 500 articoli. Adoro il tuo approccio in termini di chiarezza, ma cosa ne pensi della performance? –

+1

@LuisU. questo dipende molto dalla tua applicazione, l'unico modo per sapere è profilare il tuo codice (ad esempio con il comando 'timeit' in IPython, o con il [timeit] (https://docs.python.org/2/library/timeit .html) .Se nel caso in cui si stampa semplicemente qualcosa, si esegue un calcolo pesante, tutto il resto se trascurabile.Posso anche immaginare che parlare con il proprio database richiederà molto più tempo rispetto a un semplice ciclo di ciclo in 5 città. –

+0

Per favore [non iniziare l'ottimizzazione] (http://c2.com/cgi/wiki?PrematureOptimization) prima di sapere che c'è un problema, prova prima a scrivere codice chiaro e manutenibile, ma se vuoi ottimizzare, inizia ottimizzando l'algoritmo, ad esempio potresti cambiare 'per città in lista_di_città' (che ha tempo di calcolo lineare con la lunghezza della lista), per' città in set_of_cities' (che ha tempo di esecuzione costante) .Solo se è ancora per rallentare, iniziare a profilare tutte le linee e iniziare a preoccuparsi della velocità dei loop Python rispetto alle funzioni integrate come "qualsiasi". –

Problemi correlati