Menghitung jumlah True Boolean dalam Daftar Python

153

Saya punya daftar Boolean:

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

dan saya mencari cara untuk menghitung jumlah Truedalam daftar (jadi dalam contoh di atas, saya ingin kembali menjadi 3.) Saya telah menemukan contoh mencari jumlah kemunculan elemen-elemen tertentu, tetapi apakah ada lebih cara efisien untuk melakukannya karena saya bekerja dengan Boolean? Saya sedang memikirkan sesuatu yang analog dengan allatau any.

acs
sumber
Seperti jika Anda ingat bagaimana penghitungan bit dilakukan dalam perangkat keras menggunakan assembler saja.
Vladislavs Dovgalecs

Jawaban:

208

Truesama dengan 1.

>>> sum([True, True, False, False, False, True])
3
Ignacio Vazquez-Abrams
sumber
23
Itu tidak idiomatis dan membuat "penyalahgunaan" jenis paksaan bool.
Jan Segre
24
@ Jan Segre, tidak ada paksaan, bool adalah tipe integer.
panda-34
25
@ panda-34, saya cek dan issubclass(bool, int)ternyata tahan, jadi tidak ada paksaan.
Jan Segre
153

listmemiliki countmetode:

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

Ini sebenarnya lebih efisien daripada sum, juga lebih eksplisit tentang maksudnya, jadi tidak ada alasan untuk menggunakan 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
sumber
2
Saya tidak dapat menghitung nilai Salah jika ada nilai 0 juga
Kostanos
10
Anda tidak dapat menggunakan sumjawaban lain jika Anda memiliki nilai "benar" lain selain 1 atau Benar juga. Selain itu, pertanyaan tidak menyebutkan apa pun kecuali Trueatau False.
Mark Tolonen
43

Jika Anda hanya peduli dengan konstanta True, yang sederhana sumbaik-baik saja. Namun, perlu diingat bahwa dalam Python nilai-nilai lain juga dievaluasi True. Solusi yang lebih kuat adalah dengan menggunakan boolbuiltin:

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

UPDATE: Berikut ini adalah solusi lain yang sama kuatnya yang memiliki keuntungan lebih transparan:

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

PS Python trivia: True bisa benar tanpa menjadi 1. Peringatan: jangan coba-coba ini di tempat kerja!

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

Jauh lebih jahat:

True = False
Ned Deily
sumber
Oke, saya melihat contoh Anda, dan saya melihat apa yang dilakukannya. Terlepas dari LOL-ness itu, apakah sebenarnya ada alasan bagus untuk melakukan apa yang telah Anda tunjukkan di sini?
acs
1
Ya, untuk bagian atas. Seperti yang saya sebutkan, tes Python untuk "true" (seperti dalam sebuah ifpernyataan) lebih rumit dari sekedar pengujian True. Lihat docs.python.org/py3k/library/stdtypes.html#truth . Itu True = 2hanya untuk menegaskan bahwa konsep "benar" lebih kompleks; dengan sedikit kode tambahan (yaitu menggunakan bool()) Anda dapat membuat solusinya lebih kuat dan lebih umum.
Ned Deily
9
Di Python 3, Truedan Falsemerupakan kata kunci dan Anda tidak dapat mengubahnya.
ThePiercingPrince
8

Anda bisa menggunakan sum():

>>> sum([True, True, False, False, False, True])
3
Blender
sumber
5

Demi kelengkapan saja ( sumbiasanya lebih disukai), saya ingin menyebutkan bahwa kita juga dapat menggunakan filteruntuk mendapatkan nilai-nilai kebenaran. Dalam kasus biasa, filtermenerima fungsi sebagai argumen pertama, tetapi jika Anda melewatinya None, itu akan memfilter untuk semua nilai "benar". Fitur ini agak mengejutkan, tetapi didokumentasikan dengan baik dan berfungsi baik di Python 2 dan 3.

Perbedaan antara versi, adalah bahwa dalam Python 2 filtermengembalikan daftar, sehingga kita dapat menggunakan len:

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

Namun dalam Python 3, filtermengembalikan sebuah iterator, jadi kita tidak dapat menggunakan len, dan jika kita ingin menghindari penggunaan sum(untuk alasan apa pun) kita perlu menggunakan konversi iterator ke daftar (yang membuatnya jauh lebih tidak cantik):

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

Setelah membaca semua jawaban dan komentar pada pertanyaan ini, saya berpikir untuk melakukan percobaan kecil.

Saya menghasilkan 50.000 boolean acak dan memanggil sumdan countterus menggunakannya.

Inilah hasil saya:

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

Untuk memastikannya, saya mengulanginya beberapa kali:

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

Dan seperti yang Anda lihat, count3 kali lebih cepat dari sum. Jadi saya akan menyarankan untuk menggunakan countseperti yang saya lakukan di count_it.

Versi Python: 3.6.7
Core CPU: 4
Ukuran RAM: 16 GB
OS: Ubuntu 18.04.1 LTS

GMishx
sumber
3

Lebih aman untuk dijalankan boolterlebih dahulu. Ini mudah dilakukan:

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

Kemudian Anda akan menangkap semua yang Python anggap Benar atau Salah ke dalam ember yang sesuai:

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

Jika Anda suka, Anda dapat menggunakan pemahaman:

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

sumber
1

Saya lebih suka len([b for b in boollist if b is True])(atau setara dengan ekspresi generator), karena cukup jelas. Kurang 'ajaib' daripada jawaban yang diajukan oleh Ignacio Vazquez-Abrams.

Atau, Anda dapat melakukan ini, yang masih mengasumsikan bahwa bool dapat dikonversi ke int, tetapi tidak membuat asumsi tentang nilai True: ntrue = sum(boollist) / int(True)

kampu
sumber
Solusi Anda memiliki setidaknya dua masalah. Satu, ia menderita masalah ketahanan yang sama; Anda dapat memperbaikinya dengan hanya mengubah tes if b. Tetapi, yang lebih penting, Anda membangun daftar membuang yang membutuhkan semua nilai dalam memori sekaligus dan Anda tidak dapat menggunakan lendengan ekspresi generator. Lebih baik hindari praktik semacam itu sehingga solusinya dapat berkembang.
Ned Deily
@Ned Deily: if bbenar-benar salah. Itu hanya akan benar jika pertanyaannya adalah tentang item yang mengevaluasi sebagai True, bukan boolean Sejati yang sebenarnya. Saya mengambil poin kedua Anda. Kalau begitu ada variasinya sum(1 if b is True else 0 for b in boollist).
kampu
Seperti yang saya catat di tempat lain, tidak jelas bagi saya dari pertanyaan apakah OP benar-benar berarti hanya menghitung objek bertipe bool dengan nilai 1 atau berarti set nilai yang lebih besar dan umumnya lebih bermanfaat yang mengevaluasi true. Jika yang pertama, maka tes identitas adalah pendekatan yang tepat tetapi juga membatasi. Objek tipe bool adalah bebek agak aneh di Python, tambahan yang relatif baru untuk bahasa. Dalam hal apapun saya akan pergi untuk yang lebih sederhana:sum(1 for b in boollist if b is True)
Ned Deily