Suponiendo que tengo una lista con una gran cantidad de elementos.
l = [ 1, 4, 6, 30, 2, ... ]
Quiero obtener la cantidad de elementos de esa lista, donde un elemento debe cumplir cierta condición. 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 una gran cantidad de elementos, creo que crear una nueva lista para el resultado filtrado es solo una pérdida de memoria. Por eficiencia, en mi humilde opinión, la llamada anterior no puede ser mejor que:
count = 0
for i in l:
if my_condition(l):
count += 1
¿Existe alguna forma de estilo funcional para lograr obtener el número de elementos que satisfacen cierta condición sin generar una lista temporal?
Gracias por adelantado.

Respuestas:
Puedes usar una expresión generadora :
>>> l = [1, 3, 7, 2, 6, 8, 10] >>> sum(1 for i in l if i % 4 == 3) 2o incluso
>>> sum(i % 4 == 3 for i in l) 2que utiliza el hecho de que
int(True) == 1.Alternativamente, puede usar
itertools.imap(python 2) o simplementemap(python 3):>>> def my_condition(x): ... return x % 4 == 3 ... >>> sum(map(my_condition, l)) 2fuente
startpredeterminado es 0, por lo que la primera adición esTrue + 0, ¿no?int(True)sea.int("1") == 1también, pero eso no significa que puedas hacerlo"1" + 0. Lo que importa es cómo Python evalúainteger + Trueointeger + False.booles una subclase deinty usted, por lo que puede agregar bools e ints fácilmente (conTrueun valor de 1 yFalseun valor de 0).int(True) == 1, pero su punto queint("1") == 1prueba que abreviarlo de esa manera puede implicar cosas que no son ciertas.Quiere una comprensión del generador 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)) # -> 14O usar
itertools.imap(aunque creo que la lista explícita y las expresiones generadoras se ven algo más Pythonic).Tenga en cuenta que, aunque no es obvio en el
sumejemplo, puede componer muy bien las comprensiones del generador. 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 # -> 83333333333500000Lo 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.
fuente
Esto también se puede hacer usando
reducesi prefiere la programación funcionalreduce(lambda count, i: count + my_condition(i), l, 0)De esta manera, solo hace 1 paso y no se genera una lista intermedia.
fuente
podrías hacer algo como:
l = [1,2,3,4,5,..] count = sum(1 for i in l if my_condition(i))que solo agrega 1 por cada elemento que cumple la condición.
fuente
from itertools import imap sum(imap(my_condition, l))fuente
imapno está disponible con Python actual.