การนับจำนวน True Booleans ในรายการ Python


152

ฉันมีรายชื่อ Booleans:

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

และฉันกำลังมองหาวิธีที่จะนับจำนวนTrueในรายการ (ดังนั้นในตัวอย่างข้างต้นฉันต้องการให้ผลตอบแทนเป็น3) ฉันได้พบตัวอย่างของการมองหาจำนวนการเกิดขึ้นขององค์ประกอบเฉพาะ แต่มีมากกว่า วิธีที่มีประสิทธิภาพในการทำตั้งแต่ฉันทำงานกับ Booleans? ฉันคิดว่าบางสิ่งบางอย่างที่คล้ายคลึงกับหรือallany


เช่นถ้าคุณจำได้ว่าการนับบิตทำได้ในฮาร์ดแวร์โดยใช้แอสเซมเบลอร์เท่านั้น
Vladislavs Dovgalecs

คำตอบ:


207

True1จะมีค่าเท่ากับ

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

23
ที่ไม่ได้เป็นสำนวนและทำให้ "การละเมิด" ของการข่มขู่ประเภทบูล
Jan Segre

24
@Jan Segre ไม่มีการบีบบังคับ bool เป็นประเภทจำนวนเต็ม
panda-34

25
@ panda-34 ฉันตรวจสอบและตามissubclass(bool, int)จริงแล้วไม่มีการบีบบังคับ
Jan Segre

153

listมีcountวิธีการ:

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

อันนี้มีประสิทธิภาพมากกว่าsumและชัดเจนเกี่ยวกับเจตนาดังนั้นจึงไม่มีเหตุผลที่จะใช้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
ฉันไม่สามารถนับค่าเท็จถ้ามีค่า 0 ด้วย
Kostanos

10
คุณไม่สามารถใช้sumคำตอบอื่น ๆ หากคุณมีค่า "จริง" อื่น ๆ นอกเหนือจาก 1 หรือ True อย่างใดอย่างหนึ่ง นอกจากนี้แล้วคำถามไม่ได้พูดถึงอะไร แต่หรือTrue False
Mark Tolonen

43

หากคุณเกี่ยวข้องกับค่าคงที่เพียงอย่างเดียวก็Trueง่ายsumดี อย่างไรก็ตามโปรดจำไว้ว่าใน Python มีค่าอื่น ๆTrueเช่นกัน วิธีแก้ปัญหาที่แข็งแกร่งกว่าคือการใช้boolbuiltin:

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

UPDATE: ต่อไปนี้เป็นโซลูชันที่มีประสิทธิภาพในลักษณะเดียวกันซึ่งมีความได้เปรียบในการมีความโปร่งใสมากขึ้น:

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

PS Python เรื่องไม่สำคัญ: True อาจเป็นจริงโดยไม่ต้องเป็น 1 คำเตือน: อย่าลองสิ่งนี้ในที่ทำงาน!

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

ความชั่วร้ายอีกมากมาย:

True = False

ตกลงฉันเห็นตัวอย่างของคุณและฉันเห็นสิ่งที่กำลังทำ นอกเหนือจาก LOL-ness แล้วมีเหตุผลที่ดีที่จะทำสิ่งที่คุณแสดงที่นี่หรือไม่?
acs

1
ใช่สำหรับส่วนบน ดังที่ฉันได้ระบุไว้การทดสอบ Python สำหรับ "จริง" (ดังในifคำสั่ง) นั้นซับซ้อนกว่าการทดสอบเพียงTrueอย่างเดียว ดูdocs.python.org/py3k/library/stdtypes.html#truth True = 2เป็นเพียงเพื่อเสริมสร้างว่าแนวคิดของ "ความจริง" มีความซับซ้อนมากขึ้น ด้วยรหัสพิเศษเล็กน้อย (เช่นใช้bool()) คุณสามารถทำให้โซลูชันมีความแข็งแกร่งและเป็นทั่วไปมากขึ้น
Ned Deily

9
ใน Python 3 TrueและFalseเป็นคำหลักและคุณไม่สามารถเปลี่ยนแปลงได้
ThePiercingPrince ตั้งแต่


5

เพื่อประโยชน์ของความสมบูรณ์ ( sumโดยปกติแล้วจะดีกว่า) ฉันต้องการพูดถึงว่าเรายังสามารถใช้filterเพื่อรับค่าความจริง ในกรณีปกติfilterยอมรับฟังก์ชั่นเป็นอาร์กิวเมนต์แรก แต่ถ้าคุณผ่านNoneมันจะกรองค่าทั้งหมด "ความจริง" คุณลักษณะนี้ค่อนข้างน่าแปลกใจ แต่มีการบันทึกไว้เป็นอย่างดีและใช้ได้ทั้ง Python 2 และ 3

ความแตกต่างระหว่างรุ่นคือใน Python 2 filterจะส่งคืนรายการดังนั้นเราจึงสามารถใช้len:

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

แต่ใน Python 3 filterคืนค่าตัววนซ้ำดังนั้นเราจึงใช้ไม่ได้lenและถ้าเราต้องการหลีกเลี่ยงการใช้sum(ไม่ว่าจะด้วยเหตุผลใดก็ตาม) เราจำเป็นต้องเปลี่ยนตัววนซ้ำเป็นรายการ (ซึ่งทำให้สวยน้อยกว่ามาก):

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

หลังจากอ่านคำตอบและความคิดเห็นทั้งหมดในคำถามนี้ฉันคิดว่าจะทำการทดลองขนาดเล็ก

ฉันสร้าง 50,000 booleans สุ่มและเรียกsumและcountกับพวกเขา

นี่คือผลลัพธ์ของฉัน:

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

เพียงเพื่อให้แน่ใจว่าฉันซ้ำหลายครั้ง:

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

และในขณะที่คุณสามารถดูcountเป็น 3 sumเท่าเร็วกว่า ดังนั้นผมจึงขอแนะนำให้ใช้เป็นที่ฉันได้ในcountcount_it

Python เวอร์ชั่น: 3.6.7
CPU core: 4
RAM ขนาด: 16 GB
ระบบปฏิบัติการ: Ubuntu 18.04.1 LTS


3

มันปลอดภัยกว่าที่จะเรียกใช้ผ่านboolครั้งแรก สามารถทำได้อย่างง่ายดาย:

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

จากนั้นคุณจะพบทุกสิ่งที่ Python เห็นว่าเป็น True หรือ False ในที่เก็บข้อมูลที่เหมาะสม:

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

หากคุณต้องการคุณสามารถใช้ความเข้าใจ:

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

1

ฉันชอบlen([b for b in boollist if b is True])(หรือตัวสร้างนิพจน์เทียบเท่า) เนื่องจากมันค่อนข้างอธิบายตัวเองได้ น้อย 'เสก' กว่าคำตอบที่เสนอโดย Ignacio Vazquez-Abrams

หรือคุณสามารถทำสิ่งนี้ได้ซึ่งยังถือว่าสมมติว่าบูลสามารถแปลงเป็น int ได้ แต่ไม่ได้ตั้งสมมติฐานเกี่ยวกับมูลค่าของ True: ntrue = sum(boollist) / int(True)


โซลูชันของคุณมีปัญหาอย่างน้อยสองปัญหา หนึ่งมันทนทุกข์ทรมานจากปัญหาความแข็งแกร่งเดียวกัน; if bที่คุณสามารถแก้ไขได้โดยเพียงแค่การเปลี่ยนการทดสอบเพื่อ แต่ที่สำคัญกว่านั้นคือคุณกำลังสร้างรายการทิ้งที่ต้องการให้ค่าทั้งหมดอยู่ในหน่วยความจำพร้อมกันและคุณไม่สามารถใช้lenกับนิพจน์ตัวสร้าง ดีกว่าที่จะหลีกเลี่ยงการปฏิบัติดังกล่าวเพื่อให้วิธีการแก้ปัญหาสามารถปรับขนาด
Ned Deily

@Ned Deily: if bผิดอย่างแน่นอน มันจะถูกต้องหากคำถามเกี่ยวกับรายการที่ประเมินว่าเป็น True แทนที่จะเป็นบูลีนจริง ฉันใช้จุดที่สองของคุณว่า sum(1 if b is True else 0 for b in boollist)ในกรณีที่มีตัวแปร
kampu

ดังที่ฉันได้กล่าวไว้ที่อื่นมันไม่ชัดเจนสำหรับฉันจากคำถามที่ว่า OP หมายถึงการนับเฉพาะวัตถุประเภทบูลที่มีค่า 1 หรือหมายถึงชุดของค่าที่ใหญ่กว่าและมีประโยชน์มากกว่าที่ประเมินค่าจริง หากก่อนหน้านี้การทดสอบตัวตนเป็นวิธีการที่เหมาะสม แต่ก็มีข้อ จำกัด เช่นกัน วัตถุประเภทบูลค่อนข้างเป็ดแปลกในงูหลามอยู่แล้วนอกจากนี้เมื่อเร็ว ๆ นี้นอกเหนือจากภาษา ในกรณีใด ๆ ฉันจะไปง่าย:sum(1 for b in boollist if b is True)
เน็ด Deily
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.