2013-03-13 9 views
45

Supponendo di avere una lista con un numero enorme di elementi.python: ottenere il numero di elementi dalla lista (sequenza) con determinate condizioni

l = [ 1, 4, 6, 30, 2, ... ] 

Desidero ottenere il numero di elementi da tale elenco, in cui un elemento deve soddisfare determinate condizioni. Il mio primo pensiero è stato:

count = len([i for i in l if my_condition(l)]) 

Ma se la my_condition() elenco filtrato ha anche un grande numero di elementi, penso che creando nuovo elenco per il risultato filtrato è solo spreco di memoria. Per l'efficienza, secondo me, al di sopra chiamata non può essere migliore di:

count = 0 
for i in l: 
    if my_condition(l): 
     count += 1 

C'è un modo funzionale, in stile di raggiungere per ottenere il # di elementi che soddisfano certe condizioni senza generare elenco temporaneo?

Grazie in anticipo.

+3

La scelta tra i generatori e le liste è una scelta tra tempo di esecuzione e consumo di memoria. Sareste sorpresi di quanto spesso i risultati siano contro-intuitivi se si profila il codice. L'ottimizzazione prematura è la radice di tutto il male. –

risposta

12

Si desidera un generator comprehension anziché un elenco qui.

Per esempio,

l = [1, 4, 6, 7, 30, 2] 

def my_condition(x): 
    return x > 5 and x < 20 

print sum(1 for x in l if my_condition(x)) 
# -> 2 
print sum(1 for x in range(1000000) if my_condition(x)) 
# -> 14 

Oppure utilizzare itertools.imap (anche se credo che la lista e generatore esplicite espressioni sembrano un po 'più Pythonic).

Si noti che, sebbene non sia evidente dall'esempio sum, è possibile comporre piacevolmente le estensioni del generatore. Ad esempio,

inputs = xrange(1000000)  # In Python 3 and above, use range instead of xrange 
odds = (x for x in inputs if x % 2) # Pick odd numbers 
sq_inc = (x**2 + 1 for x in odds) # Square and add one 
print sum(x/2 for x in sq_inc)  # Actually evaluate each one 
# -> 83333333333500000 

La cosa bella di questa tecnica è che è possibile specificare passi concettualmente distinte nel codice senza forzare la valutazione e archiviazione in memoria fino a quando il risultato finale viene valutato.

66

È possibile utilizzare un generator expression:

>>> l = [1, 3, 7, 2, 6, 8, 10] 
>>> sum(1 for i in l if i % 4 == 3) 
2 

o anche

>>> sum(i % 4 == 3 for i in l) 
2 

che utilizza il fatto che int(True) == 1.

In alternativa, è possibile utilizzare itertools.imap (Python 2) o semplicemente map (Python 3):

>>> def my_condition(x): 
...  return x % 4 == 3 
... 
>>> sum(map(my_condition, l)) 
2 
+4

Più precisamente, utilizza il fatto che 'True + True == 2' – mgilson

+1

@mgilson: non penso che faccia mai questo calcolo - il valore predefinito di' start' è 0, quindi la prima aggiunta è 'Vero + 0', no? – DSM

+4

Sì. Forse dovrei essere più chiaro ... Non importa cosa sia 'int (True)'. 'int (" 1 ") == 1' anche, ma questo non significa che puoi fare" 1 "+ 0'. Ciò che conta è come Python valuti 'intero + True o' intero + False'. – mgilson

1
from itertools import imap 
sum(imap(my_condition, l)) 
3

si potrebbe fare qualcosa di simile:

l = [1,2,3,4,5,..] 
count = sum(1 for i in l if my_condition(i)) 

che aggiunge solo 1 per ogni elemento che soddisfa la condizione.

4

Questo può anche essere fatto utilizzando reduce, se si preferisce la programmazione funzionale

reduce(lambda count, i: count + my_condition(i), l, 0) 

questo modo si fa solo 1 pass e nessuna lista intermedia viene generato.

Problemi correlati