Contando il numero di veri booleani in un elenco Python


153

Ho un elenco di booleani:

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

e sto cercando un modo per contare il numero di Truenella lista (quindi nell'esempio sopra, voglio che sia il ritorno 3.) Ho trovato esempi di ricerca del numero di occorrenze di elementi specifici, ma c'è un altro modo efficace per farlo dal momento che sto lavorando con i booleani? Sto pensando a qualcosa di analogo a allo any.


Ad esempio, se ricordi come è stato eseguito il conteggio dei bit nell'hardware utilizzando solo l'assemblatore.
Vladislavs Dovgalecs,

Risposte:


208

Trueè uguale a 1.

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

23
Ciò non è idiomatico e fa "abuso" del tipo coercizione di bool.
Jan Segre,

24
@Jan Segre, non c'è coercizione, bool è un tipo intero.
Panda, 34

25
@ panda-34, ho controllato e issubclass(bool, int)in effetti vale, quindi non c'è coercizione.
Jan Segre,

153

listha un countmetodo:

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

Questo è in realtà più efficiente di sum, oltre ad essere più esplicito sull'intento, quindi non c'è motivo di usare 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)

2
Non posso contare i valori falsi se c'è anche 0 valore
Kostanos

10
Non puoi usare suml'altra risposta se hai altri valori "veri" oltre a 1 o Vero. Inoltre, allora la domanda non menzionava altro che Trueo False.
Mark Tolonen,

43

Se ti preoccupi solo della costante True, un semplice sumva bene. Tuttavia, tieni presente che anche in Python vengono valutati anche altri valori True. Una soluzione più solida sarebbe quella di utilizzare l' boolintegrato:

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

AGGIORNAMENTO: Ecco un'altra soluzione altrettanto robusta che ha il vantaggio di essere più trasparente:

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

Curiosità su PS Python: True potrebbe essere vero senza essere 1. Attenzione: non provarlo al lavoro!

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

Molto più male:

True = False

Ok, vedo il tuo esempio e vedo cosa sta facendo. A parte la LOL-ness, c'è davvero una buona ragione per fare ciò che hai mostrato qui?
acs

1
Sì, per la parte superiore. Come ho indicato, il test Python per un "vero" (come in ifun'istruzione) è più complicato del semplice test per True. Vedi docs.python.org/py3k/library/stdtypes.html#truth . Il True = 2solo scopo di rafforzare il concetto di "vero" è più complesso; con un po 'di codice extra (cioè usando bool()) puoi rendere la soluzione più solida e più generale.
Ned Deily,

9
In Python 3, Truee Falsesono parole chiave e non è possibile modificarle.
ThePiercingPrince il

8

Puoi usare sum():

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

5

Solo per completezza (di sumsolito è preferibile), volevo menzionare che possiamo anche usare filterper ottenere i valori di verità. Nel solito caso, filteraccetta una funzione come primo argomento, ma se la passi None, filtrerà per tutti i valori "veritieri". Questa funzione è piuttosto sorprendente, ma è ben documentata e funziona sia in Python 2 che in 3.

La differenza tra le versioni, è che in Python 2 filterrestituisce un elenco, quindi possiamo usare len:

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

Ma in Python 3, filterrestituisce un iteratore, quindi non possiamo usarlo len, e se vogliamo evitare di usarlo sum(per qualsiasi motivo) dobbiamo ricorrere alla conversione dell'iteratore in un elenco (che lo rende molto meno carino):

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

4

Dopo aver letto tutte le risposte e i commenti su questa domanda, ho pensato di fare un piccolo esperimento.

Ho generato 50.000 booleani casuali sume countli ho chiamati e su di essi.

Ecco i miei risultati:

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

Giusto per essere sicuro, l'ho ripetuto più volte:

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

E come puoi vedere, countè 3 volte più veloce di sum. Quindi suggerirei di usare countcome ho fatto io count_it.

Versione Python: 3.6.7 Core
CPU: 4
Dimensioni RAM: 16 GB
Sistema operativo: Ubuntu 18.04.1 LTS


3

È più sicuro passare boolprima. Questo è fatto facilmente:

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

Quindi prenderai tutto ciò che Python considera True o False nel bucket appropriato:

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

Se preferisci, puoi usare una comprensione:

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

1

Preferisco len([b for b in boollist if b is True])(o l'equivalente dell'espressione del generatore), poiché è abbastanza autoesplicativo. Meno "magico" della risposta proposta da Ignacio Vazquez-Abrams.

In alternativa, puoi farlo, il che presuppone che bool sia convertibile in int, ma non fa ipotesi sul valore di True: ntrue = sum(boollist) / int(True)


La tua soluzione ha almeno due problemi. Uno, soffre dello stesso problema di robustezza; che potresti risolvere semplicemente cambiando il test in if b. Ma, cosa ancora più importante, stai costruendo un elenco usa e getta che richiede che tutti i valori siano in memoria contemporaneamente e non puoi usarli lencon un'espressione del generatore. Meglio evitare tali pratiche in modo che la soluzione possa adattarsi.
Ned Deily,

@Ned Deily: if bè esattamente sbagliato. Sarebbe corretto solo se la domanda riguardasse elementi che valutano come True, piuttosto che veri e propri booleani. Prendo il tuo secondo punto però. In quel caso c'è la variante sum(1 if b is True else 0 for b in boollist).
Kampu,

Come ho notato altrove, non mi è chiaro dalla domanda se l'OP significhi davvero contare solo oggetti di tipo bool con il valore 1 o indicare l'insieme di valori più ampio e generalmente più utile che valuta vero. Se il primo, quindi un test di identità è l'approccio giusto ma è anche limitante. Gli oggetti di tipo bool sono comunque anatre piuttosto strane in Python, un'aggiunta relativamente recente al linguaggio. In ogni caso preferirei il più semplice:sum(1 for b in boollist if b is True)
Ned Deily l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.