J'ai une liste de booléens:
[True, True, False, False, False, True]
et je cherche un moyen de compter le nombre de True
dans la liste (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 existe-t-il un moyen plus efficace de le faire puisque je travaille avec des booléens? Je pense à quelque chose d'analogue à all
ou any
.
True
est égal à 1
.
>>> sum([True, True, False, False, False, True])
3
list
a une méthode count
:
>>> [True,True,False].count(True)
2
C’est en fait plus efficace que sum
, tout en étant plus explicite sur l’intention, il n’ya 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)
Si vous êtes uniquement préoccupé par la constante True
, une simple sum
convient. Cependant, gardez à l'esprit qu'en Python, les autres valeurs sont également évaluées par True
. Une solution plus robuste consisterait à utiliser la variable bool
inté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 présente l’avantage d’être plus transparente:
>>> sum(1 for x in l if x)
3
P.S. Jeu-questionnaire en python: 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 diabolique:
True = False
Vous pouvez utiliser sum()
:
>>> sum([True, True, False, False, False, True])
3
Juste pour être complet (sum
est généralement préférable), je voulais mentionner que nous pouvons également utiliser filter
pour obtenir les valeurs de vérité. Dans le cas habituel, filter
accepte une fonction en tant que premier argument, mais si vous le transmettez à None
, il filtrera toutes les valeurs "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 est que, dans Python 2, filter
renvoie 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, filter
renvoie un itérateur. Nous ne pouvons donc pas utiliser len
. Si nous voulons éviter d'utiliser sum
(quelle que soit la raison), nous devons convertir l'itérateur en liste (ce qui le rend 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
Il est plus sûr de parcourir d'abord bool
. C'est facile à faire:
>>> sum(map(bool,[True, True, False, False, False, True]))
3
Ensuite, vous allez attraper tout ce que Python considère comme étant 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]
Je préfère len([b for b in boollist if b is True])
(ou l'équivalent générateur-expression), car c'est assez explicite. Moins "magique" que la réponse proposée par Ignacio Vazquez-Abrams.
Vous pouvez aussi faire cela, ce qui suppose toujours que bool est convertible en int, mais ne fait aucune hypothèse concernant la valeur de True: ntrue = sum(boollist) / int(True)
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 appelé sum
et count
sur 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 constater, count
est 3 fois plus rapide que sum
. Je suggère donc d'utiliser count
comme je l'ai fait dans count_it
.
Version Python: 3.6.7
Cœurs de la CPU: 4
Taille de la RAM: 16 Go
OS: Ubuntu 18.04.1 LTS