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) 2
o incluso
>>> sum(i % 4 == 3 for i in l) 2
que 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)) 2
fuente
start
predeterminado es 0, por lo que la primera adición esTrue + 0
, ¿no?int(True)
sea.int("1") == 1
también, pero eso no significa que puedas hacerlo"1" + 0
. Lo que importa es cómo Python evalúainteger + True
ointeger + False
.bool
es una subclase deint
y usted, por lo que puede agregar bools e ints fácilmente (conTrue
un valor de 1 yFalse
un valor de 0).int(True) == 1
, pero su punto queint("1") == 1
prueba 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)) # -> 14
O 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
sum
ejemplo, 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 # -> 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.
fuente
Esto también se puede hacer usando
reduce
si 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
imap
no está disponible con Python actual.