web-dev-qa-db-fra.com

Compter les éléments entiers positifs dans une liste avec Python list comprehensions

J'ai une liste d'entiers et je dois compter combien d'entre eux sont> 0.
Je le fais actuellement avec une compréhension de liste qui ressemble à ceci:

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

Cela semble être une compréhension décente mais je n'aime pas vraiment le "1"; cela ressemble un peu à un nombre magique. Existe-t-il une façon plus pythonienne de procéder?

44
fairfieldt

Si vous souhaitez réduire la quantité de mémoire, vous pouvez éviter de générer une liste temporaire en utilisant un générateur:

sum(x > 0 for x in frequencies)

Cela fonctionne car bool est une sous-classe de int:

>>> isinstance(True,int)
True

et la valeur de True est 1:

>>> True==1
True

Cependant, comme le souligne Joe Golton dans les commentaires, cette solution n'est pas très rapide. Si vous avez suffisamment de mémoire pour utiliser une liste temporaire intermédiaire, alors la solution de sth peut être plus rapide. Voici quelques timings comparant différentes solutions:

>>> 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

Attention, les résultats temporels peuvent varier selon la version de Python, du système d'exploitation ou du matériel.

Bien sûr, si vous faites des calculs sur une grande liste de nombres, vous devriez probablement utiliser NumPy:

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

Le tableau NumPy nécessite moins de mémoire que la liste équivalente Python, et le calcul peut être effectué beaucoup plus rapidement que toute solution pure Python.

76
unutbu

Un moyen un peu plus Pythonique serait d'utiliser un générateur à la place:

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

Cela évite de générer toute la liste avant d'appeler sum().

23
Greg Hewgill

Vous pouvez utiliser len() sur la liste filtrée:

len([x for x in frequencies if x > 0])
9
sth

Cela fonctionne, mais l'ajout de bools en tant que ints peut être dangereux. Veuillez prendre ce code avec un grain de sel (la maintenabilité passe en premier):

sum(k>0 for k in x)
4
Escualo

Si le tableau ne contient que des éléments> = 0 (c'est-à-dire que tous les éléments sont soit 0 ou un entier positif), vous pouvez simplement compter les zéros et soustraire ce nombre de la longueur du tableau:

len(arr) - arr.count(0)
1
ben_nuttall

Que dis-tu de ça?

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

EDIT: Avec l'inspiration de la réponse acceptée de @ ~ unutbu:

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

0
Peter Jaric