python: obtenga el número de elementos de la lista (secuencia) con cierta condición

Suponiendo que tengo una lista con gran cantidad de elementos.

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

Quiero obtener el número de elementos de esa lista, donde un elemento debe cumplir con ciertas condiciones. Mi primer pensamiento fue:

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

Pero si la lista filtrada my_condition () también tiene un gran número de elementos, creo que crear una nueva lista para el resultado filtrado es solo un desperdicio de memoria. Para eficiencia, IMHO, la llamada anterior no puede ser mejor que:

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

¿Existe alguna forma funcional de lograr el número de elementos que cumplan ciertas condiciones sin generar una lista temporal?

Gracias por adelantado.

Puedes usar una expresión generadora :

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

o incluso

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

que utiliza el hecho de que int(True) == 1 .

Alternativamente, puedes usar itertools.imap (python 2) o simplemente map (python 3):

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

Usted quiere un generador de comprensión en lugar de una lista aquí.

Por ejemplo,

 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 

O use itertools.imap (aunque creo que la lista explícita y las expresiones generadoras parecen algo más Pythonic).

Tenga en cuenta que, aunque no es obvio en el ejemplo de la sum , puede componer las interpretaciones del generador muy bien. Por ejemplo,

 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 

Lo bueno de esta técnica es que puede especificar pasos conceptualmente separados en el código sin forzar la evaluación y el almacenamiento en la memoria hasta que se evalúe el resultado final.

Esto también se puede hacer usando reduce si prefieres la progtwigción funcional.

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

De esta manera solo haces 1 paso y no se genera una lista intermedia.

usted podría hacer algo como:

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

que solo agrega 1 para cada elemento que satisface la condición.

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

Tuve un problema similar y lo resuelvo usando generadores.

También creo que esta pregunta puede ayudarlo: Filtrado de listas: comprensión de listas vs. filtro lambda +