Zählen der Anzahl der True Booleans in einer Python-Liste

152

Ich habe eine Liste von Booleschen:

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

und ich suche nach einer Möglichkeit, die Anzahl der Vorkommen Truein der Liste zu zählen (im obigen Beispiel möchte ich, dass die Rückgabe erfolgt 3). Ich habe Beispiele für die Suche nach der Anzahl der Vorkommen bestimmter Elemente gefunden, aber es gibt noch mehr Effizienter Weg, da ich mit Booleanern arbeite? Ich denke an etwas Analoges zu alloder any.

acs
quelle
Zum Beispiel, wenn Sie sich daran erinnern, wie die Bitzählung in Hardware nur mit Assembler durchgeführt wurde.
Vladislavs Dovgalecs

Antworten:

207

Trueist gleich 1.

>>> sum([True, True, False, False, False, True])
3
Ignacio Vazquez-Abrams
quelle
23
Das ist nicht idiomatisch und macht "Missbrauch" des Typs Zwang von Bool.
Jan Segre
24
@ Jan Segre, es gibt keinen Zwang, bool ist ein ganzzahliger Typ.
Panda-34
25
@ Panda-34, habe ich überprüft und issubclass(bool, int)hält in der Tat, so gibt es keinen Zwang.
Jan Segre
152

listhat eine countMethode:

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

Dies ist tatsächlich effizienter als sumund expliziter in Bezug auf die Absicht, sodass es keinen Grund gibt, Folgendes zu verwenden 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
quelle
2
Ich kann keine falschen Werte zählen, wenn es auch einen Wert von 0 gibt
Kostanos
10
Sie können sumdie andere Antwort nicht verwenden , wenn Sie neben 1 oder True auch andere "wahre" Werte haben. Außerdem erwähnte die Frage nichts anderes als Trueoder False.
Mark Tolonen
43

Wenn Sie sich nur mit der Konstante befassen True, ist eine einfache sumin Ordnung. Beachten Sie jedoch, dass in Python auch andere Werte ausgewertet werden True. Eine robustere Lösung wäre die Verwendung der booleingebauten:

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

UPDATE: Hier ist eine weitere ähnlich robuste Lösung, die den Vorteil hat, transparenter zu sein:

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

PS Python Lappalien: True könnte wahr sein , ohne 1. Warnung zu sein: nicht versuchen , diese bei der Arbeit!

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

Viel böser:

True = False
Ned Deily
quelle
Ok, ich sehe dein Beispiel und ich sehe, was es tut. Gibt es, abgesehen von der LOL-Ness, tatsächlich einen guten Grund, das zu tun, was Sie hier gezeigt haben?
acs
1
Ja, für den oberen Teil. Wie ich bereits sagte, ist der Python-Test für ein "wahres" (wie in einer ifAnweisung) komplizierter als nur das Testen auf True. Siehe docs.python.org/py3k/library/stdtypes.html#truth . Das True = 2sollte nur bekräftigen, dass das Konzept von "wahr" komplexer ist; Mit ein wenig zusätzlichem Code (dh mit bool()) können Sie die Lösung robuster und allgemeiner gestalten.
Ned Deily
9
In Python 3 sind Trueund FalseSchlüsselwörter und Sie können sie nicht ändern.
ThePiercingPrince
8

Sie können verwenden sum():

>>> sum([True, True, False, False, False, True])
3
Mixer
quelle
5

Nur der Vollständigkeit halber ( sumist normalerweise vorzuziehen) wollte ich erwähnen, dass wir auch verwenden können filter, um die wahrheitsgemäßen Werte zu erhalten. Akzeptiert im Normalfall filtereine Funktion als erstes Argument, aber wenn Sie sie übergeben None, wird nach allen "wahrheitsgemäßen" Werten gefiltert. Diese Funktion ist etwas überraschend, aber gut dokumentiert und funktioniert sowohl in Python 2 als auch in Python 3.

Der Unterschied zwischen den Versionen besteht darin, dass in Python 2 filtereine Liste zurückgegeben wird, sodass wir Folgendes verwenden können len:

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

In Python 3 wird jedoch filterein Iterator zurückgegeben, sodass wir ihn nicht verwenden lenkönnen. Wenn wir die Verwendung sum(aus irgendeinem Grund) vermeiden möchten, müssen wir den Iterator in eine Liste konvertieren (was dies viel weniger hübsch macht):

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

Nachdem ich alle Antworten und Kommentare zu dieser Frage gelesen hatte, dachte ich an ein kleines Experiment.

Ich erzeugen 50.000 zufällig booleans und genannt sumund countauf sie.

Hier sind meine Ergebnisse:

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

Nur um sicher zu gehen, habe ich es noch mehrmals wiederholt:

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

Und wie Sie sehen können, countist dreimal schneller als sum. Also würde ich vorschlagen, countwie in zu verwenden count_it.

Python-Version: 3.6.7
CPU-Kerne: 4
RAM-Größe: 16 GB
Betriebssystem: Ubuntu 18.04.1 LTS

GMishx
quelle
3

Es ist sicherer, boolzuerst durchzulaufen . Dies ist einfach zu bewerkstelligen:

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

Dann fangen Sie alles, was Python als wahr oder falsch ansieht, im entsprechenden Bucket auf:

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

Wenn Sie es vorziehen, können Sie ein Verständnis verwenden:

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

quelle
1

ich bevorzuge len([b for b in boollist if b is True]) (oder das Äquivalent zum Generatorausdruck), da es ziemlich selbsterklärend ist. Weniger "magisch" als die Antwort von Ignacio Vazquez-Abrams.

Alternativ können Sie dies tun, wobei weiterhin davon ausgegangen wird, dass bool in int konvertierbar ist, jedoch keine Annahmen über den Wert von True getroffen werden: ntrue = sum(boollist) / int(True)

Kampu
quelle
Ihre Lösung hat mindestens zwei Probleme. Erstens leidet es unter dem gleichen Robustheitsproblem; das könnten Sie beheben, indem Sie einfach den Test auf ändern if b. Noch wichtiger ist jedoch, dass Sie eine Wegwerfliste erstellen, in der alle Werte gleichzeitig gespeichert werden müssen und die Sie nicht lenmit einem Generatorausdruck verwenden können. Vermeiden Sie solche Praktiken besser, damit die Lösung skaliert werden kann.
Ned Deily
@Ned Deily: if bist genau falsch. Es wäre nur richtig, wenn die Frage sich auf Elemente beziehen würde, die als True ausgewertet werden, und nicht auf tatsächliche True-Boolesche Werte. Ich nehme jedoch Ihren zweiten Punkt. In diesem Fall gibt es die Variante sum(1 if b is True else 0 for b in boollist).
Kampu
Wie ich an anderer Stelle bemerkt habe, ist mir aus der Frage nicht klar, ob das OP wirklich bedeutet, nur Objekte vom Typ bool mit dem Wert 1 zu zählen, oder ob es sich um den größeren und allgemein nützlicheren Satz von Werten handelt, die true bewerten. Wenn erstere, dann ist ein Identitätstest der richtige Ansatz, aber er ist auch einschränkend. Objekte vom Typ Bool sind in Python sowieso ziemlich seltsame Enten, eine relativ neue Ergänzung der Sprache. Auf jeden Fall würde ich mich für das Einfachere entscheiden:sum(1 for b in boollist if b is True)
Ned Deily