Compter le nombre de vrais booléens dans une liste Python

153

J'ai une liste de booléens:

[True, True, False, False, False, True]

et je cherche un moyen de compter le nombre de Truedans la liste (donc dans l'exemple ci-dessus, je veux que le retour soit 3.) J'ai trouvé des exemples de recherche du nombre d'occurrences d'éléments spécifiques, mais y a-t-il plus moyen efficace de le faire puisque je travaille avec des booléens? Je pense à quelque chose d'analogue à allou any.

acs
la source
Comme si vous vous rappelez comment le comptage de bits était effectué dans le matériel en utilisant uniquement l'assembleur.
Vladislavs Dovgalecs

Réponses:

208

Trueest égal à 1.

>>> sum([True, True, False, False, False, True])
3
Ignacio Vazquez-Abrams
la source
23
Ce n'est pas idiomatique et fait des "abus" du type coercition de bool.
Jan Segre
24
@Jan Segre, il n'y a pas de coercition, bool est un type entier.
panda-34
25
@ panda-34, j'ai vérifié et issubclass(bool, int)tient en fait, donc il n'y a pas de coercition.
Jan Segre
153

lista une countméthode:

>>> [True,True,False].count(True)
2

C'est en fait plus efficace que sum, en plus d'être plus explicite sur l'intention, il n'y a donc aucune raison d'utiliser sum:

In [1]: import random

In [2]: x = [random.choice([True, False]) for i in range(100)]

In [3]: %timeit x.count(True)
970 ns ± 41.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [4]: %timeit sum(x)
1.72 µs ± 161 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Mark Tolonen
la source
2
Je ne peux pas compter les fausses valeurs s'il y a une valeur 0 également
Kostanos
10
Vous ne pouvez pas utiliser suml'autre réponse si vous avez d'autres valeurs «vraies» que 1 ou Vrai non plus. D'ailleurs, alors la question ne mentionnait rien d'autre que Trueou False.
Mark Tolonen
43

Si vous ne vous préoccupez que de la constante True, un simple suffit sum. Cependant, gardez à l'esprit qu'en Python, d'autres valeurs sont également évaluées True. Une solution plus robuste serait d'utiliser la fonction boolintégrée:

>>> l = [1, 2, True, False]
>>> sum(bool(x) for x in l)
3

MISE À JOUR: Voici une autre solution tout aussi robuste qui a l'avantage d'être plus transparente:

>>> sum(1 for x in l if x)
3

Anecdotes sur PS Python: cela True pourrait être vrai sans être 1. Attention: n'essayez pas cela au travail!

>>> True = 2
>>> if True: print('true')
... 
true
>>> l = [True, True, False, True]
>>> sum(l)
6
>>> sum(bool(x) for x in l)
3
>>> sum(1 for x in l if x)
3

Beaucoup plus de mal:

True = False
Ned Deily
la source
Ok, je vois votre exemple et je vois ce qu'il fait. En dehors de la LOL, y a-t-il vraiment une bonne raison de faire ce que vous avez montré ici?
acs
1
Oui, pour la partie supérieure. Comme je l'ai indiqué, le test Python pour un "vrai" (comme dans une ifdéclaration) est plus compliqué que de simplement tester True. Voir docs.python.org/py3k/library/stdtypes.html#truth . Le True = 2était juste de renforcer le concept de « vrai » est plus complexe; avec un peu de code supplémentaire (c'est-à-dire en utilisant bool()), vous pouvez rendre la solution plus robuste et plus générale.
Ned Deily
9
Dans Python 3, Trueet Falsesont des mots-clés et vous ne pouvez pas les changer.
ThePiercingPrince
8

Vous pouvez utiliser sum():

>>> sum([True, True, False, False, False, True])
3
Mixeur
la source
5

Juste pour être complet ( sumc'est généralement préférable), je voulais mentionner que nous pouvons également utiliser filterpour obtenir les valeurs de vérité. Dans le cas habituel, filteraccepte une fonction comme premier argument, mais si vous la transmettez None, elle filtrera toutes les valeurs «de vérité». Cette fonctionnalité est quelque peu surprenante, mais elle est bien documentée et fonctionne à la fois en Python 2 et 3.

La différence entre les versions, c'est qu'en Python 2 filterretourne une liste, nous pouvons donc utiliser len:

>>> bool_list = [True, True, False, False, False, True]
>>> filter(None, bool_list)
[True, True, True]
>>> len(filter(None, bool_list))
3

Mais dans Python 3, filterretourne un itérateur, donc nous ne pouvons pas utiliser len, et si nous voulons éviter d'utiliser sum(pour une raison quelconque), nous devons recourir à la conversion de l'itérateur en une liste (ce qui rend cela beaucoup moins joli):

>>> bool_list = [True, True, False, False, False, True]
>>> filter(None, bool_list)
<builtins.filter at 0x7f64feba5710>
>>> list(filter(None, bool_list))
[True, True, True]
>>> len(list(filter(None, bool_list)))
3
yoniLavi
la source
4

Après avoir lu toutes les réponses et commentaires sur cette question, j'ai pensé faire une petite expérience.

J'ai généré 50 000 booléens aléatoires et ai appelé sumet countsur eux.

Voici mes résultats:

>>> a = [bool(random.getrandbits(1)) for x in range(50000)]
>>> len(a)
50000
>>> a.count(False)
24884
>>> a.count(True)
25116
>>> def count_it(a):
...   curr = time.time()
...   counting = a.count(True)
...   print("Count it = " + str(time.time() - curr))
...   return counting
... 
>>> def sum_it(a):
...   curr = time.time()
...   counting = sum(a)
...   print("Sum it = " + str(time.time() - curr))
...   return counting
... 
>>> count_it(a)
Count it = 0.00121307373046875
25015
>>> sum_it(a)
Sum it = 0.004102230072021484
25015

Juste pour être sûr, je l'ai répété plusieurs fois:

>>> count_it(a)
Count it = 0.0013530254364013672
25015
>>> count_it(a)
Count it = 0.0014507770538330078
25015
>>> count_it(a)
Count it = 0.0013344287872314453
25015
>>> sum_it(a)
Sum it = 0.003480195999145508
25015
>>> sum_it(a)
Sum it = 0.0035257339477539062
25015
>>> sum_it(a)
Sum it = 0.003350496292114258
25015
>>> sum_it(a)
Sum it = 0.003744363784790039
25015

Et comme vous pouvez le voir, countc'est 3 fois plus rapide que sum. Je suggérerais donc d'utiliser countcomme je l'ai fait dans count_it.

Version Python: 3.6.7 Cœurs de
processeur: 4
Taille de RAM: 16 Go
OS: Ubuntu 18.04.1 LTS

GMishx
la source
3

Il est plus sûr de passer en boolpremier. Cela se fait facilement:

>>> sum(map(bool,[True, True, False, False, False, True]))
3

Ensuite, vous attraperez tout ce que Python considère comme vrai ou faux dans le compartiment approprié:

>>> allTrue=[True, not False, True+1,'0', ' ', 1, [0], {0:0}, set([0])]
>>> list(map(bool,allTrue))
[True, True, True, True, True, True, True, True, True]

Si vous préférez, vous pouvez utiliser une compréhension:

>>> allFalse=['',[],{},False,0,set(),(), not True, True-1]
>>> [bool(i) for i in allFalse]
[False, False, False, False, False, False, False, False, False]

la source
1

Je préfère len([b for b in boollist if b is True])(ou l'équivalent de Generator-Expression), car c'est assez explicite. Moins «magique» que la réponse proposée par Ignacio Vazquez-Abrams.

Vous pouvez également le faire, ce qui suppose toujours que bool est convertible en int, mais ne fait aucune hypothèse sur la valeur de True: ntrue = sum(boollist) / int(True)

kampu
la source
Votre solution a au moins deux problèmes. Premièrement, il souffre du même problème de robustesse; que vous pouvez corriger en changeant simplement le test en if b. Mais, plus important encore, vous construisez une liste jetable exigeant que toutes les valeurs soient en mémoire à la fois et que vous ne pouvez pas utiliser lenavec une expression de générateur. Mieux vaut éviter de telles pratiques afin que la solution puisse évoluer.
Ned Deily
@Ned Deily: if best tout à fait faux. Ce ne serait correct que si la question portait sur les éléments évalués comme True, plutôt que sur les vrais booléens True. Je prends cependant votre deuxième point. Dans ce cas, il y a la variante sum(1 if b is True else 0 for b in boollist).
kampu
Comme je l'ai noté ailleurs, la question de savoir si l'OP signifie vraiment ne compter que les objets de type bool avec la valeur 1 ou signifie l'ensemble de valeurs le plus grand et généralement le plus utile qui évalue true. Si c'est le premier, un test d'identité est la bonne approche, mais il est également limitatif. Les objets de type bool sont de toute façon des canards assez étranges en Python, un ajout relativement récent au langage. En tout cas, j'irais pour le plus simple:sum(1 for b in boollist if b is True)
Ned Deily