¿Cómo contar elementos no nulos en un iterable?

Estoy buscando una solución Pythonic mejor / más para el siguiente fragmento de código

count = sum(1 for e in iterable if e) 

 len(filter(None, iterable)) 

Usar None como el predicado para el filter solo dice que se debe usar la veracidad de los elementos. (quizás más claro sería len(filter(bool, iterable)) )

Honestamente, no puedo pensar en una mejor manera de hacerlo que en la que tienes.

Bueno, supongo que la gente podría discutir sobre “mejor”, pero creo que es poco probable que encuentre algo más corto, más simple y más claro.

La mayoría de Pythonic es escribir una pequeña función auxiliar y colocarla en su confiable módulo de “utilidades” (o submódulo del paquete apropiado, cuando tenga suficiente ;-):

 import itertools as it def count(iterable): """Return number of items in iterable.""" return sum(1 for _ in iterable) def count_conditional(iterable, predicate=None): """Return number of items in iterable that satisfy the predicate.""" return count(it.ifilter(predicate, iterable)) 

Exactamente la forma en que elija implementar estas utilidades es menos importante (puede elegir en cualquier momento recodificar algunas de ellas en Cython, por ejemplo, si algunos perfiles en una aplicación usando las utilidades lo muestran útil): la clave es tenerlos como su propia biblioteca útil de funciones de utilidad, con los nombres y los patrones de llamada que le gustan, para hacer que su importante código de nivel de aplicación sea ​​más claro, más legible y más conciso que si lo rellenara con todas las contorsiones en línea.

 sum(not not e for e in iterable) 

Este no es el más rápido, pero puede ser útil para el código de golf.

 sum(map(bool, iterable)) 

Probablemente, la forma más pythonica es escribir código que no necesite la función de conteo.

Por lo general, lo más rápido es escribir el estilo de funciones con el que mejor se desempeñan y continuar refinando su estilo.

Escribir una vez leer con frecuencia el código.

Por cierto, tu código no hace lo que dice tu título. Contar no 0 elementos no es simple, considerando errores de redondeo en números flotantes, que Falso es 0 ..

Si no tiene valores de punto flotante en la lista, esto podría hacerlo:

 def nonzero(seq): return (item for item in seq if item!=0) seq = [None,'', 0, 'a', 3,[0], False] print seq,'has',len(list(nonzero(seq))),'non-zeroes' print 'Filter result',len(filter(None, seq)) """Output: [None, '', 0, 'a', 3, [0], False] has 5 non-zeroes Filter result 3 """ 

Si solo estás tratando de ver si el iterable no está vacío, entonces esto probablemente ayudaría:

 def is_iterable_empty(it): try: iter(it).next() except StopIteration: return True else: return False 

Las otras respuestas tomarán O (N) tiempo para completar (y algunas tomarán O (N) de memoria; ¡buen ojo, John!). Esta función lleva tiempo O (1). Si realmente necesitas la longitud, entonces las otras respuestas te ayudarán más.

Aquí hay una solución con O (n) runtime y O (1) memoria adicional:

 count = reduce(lambda x,y:x+y, imap(lambda v: v>0, iterable)) 

¡Espero que ayude!

Como se indica en los comentarios, el título es algo disonante con la pregunta. Si insistiéramos en el título, es decir, contando los elementos que no son nulos, la solución del OP podría modificarse para:

 count = sum(1 for e in iterable if e is not None)