2012-10-07 11 views
74

Mam listę wartości logicznych:Zliczanie prawdziwej wartości logiczne w Pythonie listy

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

i szukam sposobu, aby policzyć True na liście (więc w powyższym przykładzie, Chcę, aby powrót był 3.) Znalazłem przykłady poszukiwania liczby wystąpień określonych elementów, ale czy istnieje bardziej skuteczny sposób, aby to zrobić, ponieważ pracuję z Booleans? Zastanawiam się nad czymś analogicznym do all lub any.

+0

Tak jakbyś pamiętał, jak liczenie bitów było wykonywane na sprzęcie tylko za pomocą asemblera. –

Odpowiedz

108

True jest równa 1.

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

To nie jest idiomatyczne i powoduje "nadużycie" przymusu typu bool. –

+15

@Jan Segre, nie ma przymusu, bool jest typem całkowitym. –

+13

@ panda-34, sprawdziłem i 'issubclass (bool, int)' faktycznie trzyma, więc nie ma przymusu. –

6

Można użyć sum():

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

Jeśli chodzi tylko o stałej True, prosty sum jest w porządku. Należy jednak pamiętać, że w Pythonie inne wartości są również oceniane jako True. Bardziej wytrzymałe rozwiązanie byłoby użyć bool polecenie wbudowane:

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

UPDATE: Oto kolejny podobnie solidne rozwiązanie, które ma tę zaletę, że są bardziej przejrzyste:

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

PS: Python: Truemoże być prawdą bez bycia 1. Ostrzeżenie: nie próbuj tego w pracy!

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

Znacznie bardziej zło:

True = False 
+0

Ok, widzę twój przykład i widzę, co robi. Oprócz LOL-u, czy istnieje naprawdę dobry powód, by zrobić to, co tu pokazałeś? – acs

+0

Tak, dla górnej części. Jak wskazałem, test Pythona dla "prawdziwego" (jak w przypadku instrukcji "if") jest bardziej skomplikowany niż testowanie dla 'True'. Zobacz http://docs.python.org/py3k/library/stdtypes.html#truth. "True = 2" miało tylko wzmocnić to, że pojęcie "prawda" jest bardziej złożone; z niewielkim dodatkowym kodem (tj. za pomocą 'bool()') możesz sprawić, że rozwiązanie będzie bardziej niezawodne i bardziej ogólne. –

+7

W Pythonie 3 słowa "prawda" i "fałsz" są słowami kluczowymi i nie można ich zmienić. – ThePiercingPrince

1

Wolę len([b for b in boollist if b is True]) (lub równowartość generator-wyrażenie), ponieważ jest to dość oczywiste. Mniej "magiczne" niż odpowiedź zaproponowana przez Ignacio Vazquez-Abrams.

Alternatywnie, można to zrobić, który nadal zakłada, że ​​bool jest convertable do int, ale nie daje żadnych założeń co do wartości TRUE: ntrue = sum(boollist)/int(True)

+0

Twoje rozwiązanie ma co najmniej dwa problemy. Po pierwsze, cierpi na tę samą kwestię solidności; które możesz naprawić zmieniając test na 'if b'. Ale, co ważniejsze, konstruujesz listę odrzuceń, która wymaga, aby wszystkie wartości znalazły się w pamięci jednocześnie i nie możesz użyć 'len' z wyrażeniem generatora. Lepiej unikać takich praktyk, aby rozwiązanie mogło się skalować. –

+0

@Ned Deily: 'if b' jest dokładnie błędny. Byłoby to poprawne tylko wtedy, gdyby pytanie dotyczyło przedmiotów, które oceniają jako Prawdziwe, a nie rzeczywistych Prawdziwych Booleans. Podejmuję jednak drugą kwestię. W takim przypadku istnieje wariant 'sum (1, jeśli b jest True równy 0 dla b w boollist)'. – kampu

+0

Jak zauważyłem w innym miejscu, nie jest dla mnie jasne, czy OP naprawdę oznacza zliczanie tylko obiektów typu bool o wartości 1 lub oznacza większy i ogólnie bardziej przydatny zbiór wartości, które są prawdziwe. Jeśli to pierwsze, to test tożsamości jest właściwym podejściem, ale także ogranicza. Przedmioty typu bool są w każdym razie raczej dziwnymi kaczkami w Pythonie, stosunkowo nowym dodatkiem do języka. W każdym razie wybrałbym prostszą: 'suma (1 dla b w boollistie, jeśli b jest prawdziwa)' –

73

list ma count metody:

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

Nie mogę zliczyć wartości fałszywych, jeśli istnieje wartość 0 również – Kostanos

+2

Nie można użyć 'sumy 'z inna odpowiedź, jeśli masz inne "prawdziwe" wartości oprócz 1 lub Prawda albo. Poza tym w pytaniu nie wspomniano nic oprócz "Prawda" lub "Fałsz". –

2

Bezpieczniej jest najpierw przejść przez bool. Można to łatwo zrobić:

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

Wtedy złapać wszystko, Python uważa Prawda czy fałsz do odpowiedniego wiadra:

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

Jeśli wolisz, możesz użyć zrozumieniem:

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

Tylko ze względu na kompletność (zwykle najlepiej jest sum), chciałem wspomnieć, że możemy również użyć filter, aby uzyskać wartości prawdy.W zwykłym przypadku filter akceptuje funkcję jako pierwszy argument, ale jeśli przekażesz ją jako None, będzie filtrować wszystkie wartości "prawda". Funkcja ta jest nieco zaskakujące, ale jest dobrze udokumentowane i działa zarówno w Python 2 i 3.

Różnica między wersjami, jest to, że w Pythonie 2 filter zwraca listę, więc możemy użyć len:

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

Ale w Pythonie 3, filter zwraca iterator, więc nie możemy użyć len, a jeśli chcemy uniknąć użycia sum (z jakiegokolwiek powodu), musimy uciec się do konwersji iteratora do listy (co czyni to znacznie mniejszym ładna):

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