2010-05-24 12 views
34

Tengo una lista de enteros y necesito contar cuántos de ellos son> 0.
Actualmente estoy haciendo una lista de comprensión que se ve así:Contando elementos enteros positivos en una lista con la lista de Python comprensiones

sum([1 for x in frequencies if x > 0]) 

Parece una comprensión decente pero realmente no me gusta el "1"; parece un poco un número mágico. ¿Hay una forma más pitonesa de hacer esto?

+2

contando elementos distintos de cero no es el mismo que elementos de recuento> 0. El título debe modificarse en consecuencia – joaquin

+0

Actualicé el título de su pregunta para que refleje su contenido. Espero que esto esté bien contigo. – EOL

Respuesta

63

Si desea reducir la cantidad de memoria, se puede evitar la generación de una lista temporal mediante el uso de un generador:

sum(x > 0 for x in frequencies) 

Esto funciona porque bool es una subclase de int:

>>> isinstance(True,int) 
True 

y el valor True es 1:

>>> True==1 
True 

Sin embargo, como señala Joe Golton en los comentarios, esta solución no es muy rápida. Si tiene suficiente memoria para usar una lista temporal intermedia, entonces sth's solution puede ser más rápido. Aquí están algunos tiempos comparando diversas soluciones:

>>> frequencies = [random.randint(0,2) for i in range(10**5)] 

>>> %timeit len([x for x in frequencies if x > 0]) # sth 
100 loops, best of 3: 3.93 ms per loop 

>>> %timeit sum([1 for x in frequencies if x > 0]) 
100 loops, best of 3: 4.45 ms per loop 

>>> %timeit sum(1 for x in frequencies if x > 0) 
100 loops, best of 3: 6.17 ms per loop 

>>> %timeit sum(x > 0 for x in frequencies) 
100 loops, best of 3: 8.57 ms per loop 

Tenga en cuenta que los resultados TimeIt pueden variar dependiendo de la versión de Python, el sistema operativo o hardware.

Por supuesto, si usted está haciendo matemáticas en una larga lista de números, probablemente debería estar utilizando NumPy:

>>> frequencies = np.random.randint(3, size=10**5) 
>>> %timeit (frequencies > 0).sum() 
1000 loops, best of 3: 669 us per loop 

La matriz NumPy requiere menos memoria que la lista de Python equivalente, y el cálculo puede ser se realizó mucho más rápido que cualquier solución pura de Python.

+2

Una variación: [x> 0 para x en frecuencias] .count (Verdadero) –

+3

@Peter: tenga en cuenta que su sugerencia se repite dos veces sobre los datos; una vez para construir la lista de salida, y dos veces para contar los valores verdaderos. – tzot

+0

@ ΤΖΩΤΖΙΟΥ: Sí, por supuesto, ¡gracias por la información! –

6

Usted podría utilizar len() en la lista filtrada:

len([x for x in frequencies if x > 0]) 
+2

aún mejor, para usar un generador (banda [y]) –

+1

Puede usar un filtro con esto para que se vea más claro. len (filtro (lambda x: x> 0, frecuencias)) –

+2

@valya: Eso no funcionará con un generador – sth

18

Una forma un poco más Pythonic sería el uso de un generador en su lugar:

sum(1 for x in frequencies if x > 0) 

Esto evita la generación de toda la lista antes de llamar sum().

+0

+1 porque esta es una manera comúnmente pasada por alto de hacer una comprensión. Si está evaluando una comprensión de lista desde dentro de una llamada a función, puede omitir '()'. – jathanism

+0

Se rompe si ninguno de los elementos coincide con los criterios. – FogleBird

+0

@FogleBird: el 'sum()' de un generador vacío devuelve 0. –

0

¿Qué tal esto?

reduce(lambda x, y: x+1 if y > 0 else x, frequencies)

EDIT: Con la inspiración de la respuesta aceptada de @ ~ unutbu:

reduce(lambda x, y: x + (y > 0), frequencies)

+0

Ojalá tuviera un comentario para ir con ese voto negativo para aprender por mis errores. ¿Por favor? –

+0

Parece haber una tendencia desde las funciones lambda hacia las listas de comprensión. – fairfieldt

+1

No fui de los que te rechazaron; sin embargo, me doy cuenta de que la gente tiende a fruncir el ceño al decir "reducir", eliminarla, etc. (según la proclamación de Guido). Me gusta 'reducir', pero también desaprovecho su uso en este caso, ya que la variante' sum (x> 0 ...) 'me parece más directa. – tzot

4

Esto funciona, pero la adición de bool s como int s puede ser peligroso. Por favor, tome este código con un grano de sal (la facilidad de mantenimiento va primero):

sum(k>0 for k in x) 
+2

Agregar booleanos como enteros está garantizado para trabajar en Python 2 y 3: http://stackoverflow.com/questions/2764017/is-false-0-and-true-1-in-python-an-implementation-detail-or -guaranteed-by-t – EOL

+0

+1 para la advertencia, sin embargo. :) – EOL

0

Si la matriz solo contiene elementos> = 0 (es decirtodos los elementos son 0 o un número entero positivo), entonces puede simplemente contar los ceros y restar este número formar la longitud de la matriz:

len(arr) - arr.count(0) 
Cuestiones relacionadas