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?
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.
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()
.
Vous pouvez utiliser len()
sur la liste filtrée:
len([x for x in frequencies if x > 0])
Cela fonctionne, mais l'ajout de bool
s en tant que int
s peut être dangereux. Veuillez prendre ce code avec un grain de sel (la maintenabilité passe en premier):
sum(k>0 for k in x)
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)
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)