Подсчет количества истинных логических значений в списке Python

153

У меня есть список логических:

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

и я ищу способ подсчитать количество Trueв списке (поэтому в приведенном выше примере я хочу, чтобы возвращение было 3.) Я нашел примеры поиска количества вхождений определенных элементов, но есть ли более эффективный способ сделать это, так как я работаю с Booleans? Я думаю о чем-то аналогичном allили any.

картографическая служба ввс
источник
Например, если вы помните, как подсчет битов выполнялся на аппаратном уровне с использованием только ассемблера.
Владислав Довгальец

Ответы:

208

Trueравно 1.

>>> sum([True, True, False, False, False, True])
3
Игнасио Васкес-Абрамс
источник
23
Это не идиоматично и делает «злоупотребление» типовым принуждением bool.
Ян Сегре
24
@ Ян Сегре, нет принуждения, тип bool целочисленный.
panda-34
25
@ panda-34, я проверил и issubclass(bool, int)фактически держит, так что никакого принуждения нет.
Ян Сегре
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.
Марк Толонен
43

Если вас интересует только константа True, простой sum- это хорошо. Однако имейте в виду, что в Python оцениваются и другие значения True. Более надежным решением будет использование boolвстроенного:

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

ОБНОВЛЕНИЕ: Вот еще одно столь же надежное решение, которое имеет преимущество в большей прозрачности:

>>> 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-ности, есть ли на самом деле хорошая причина делать то, что вы здесь показали?
ACS
1
Да, для верхней части. Как я уже говорил, проверка Python на «истину» (как в ifутверждении) сложнее, чем просто проверка True. См. Docs.python.org/py3k/library/stdtypes.html#truth . Это True = 2было только для того, чтобы подчеркнуть, что понятие «правда» является более сложным; добавив немного кода (т.е. используя bool()), вы можете сделать решение более надежным и общим.
Нед Дейли
9
В Python 3 есть Trueи Falseключевые слова, и вы не можете их изменить.
ThePiercingPrince
8

Вы можете использовать sum():

>>> sum([True, True, False, False, False, True])
3
смеситель
источник
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
yoniLavi
источник
4

Прочитав все ответы и комментарии по этому вопросу, я подумал сделать небольшой эксперимент.

Я создал 50000 случайных булевы и называется 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. Поэтому я бы предложил использовать countкак я сделал в count_it.

Версия Python: 3.6.7
Ядра процессора: 4 Объем
оперативной памяти: 16 ГБ
ОС: Ubuntu 18.04.1 LTS

GMishx
источник
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])(или эквивалент выражения генератора), поскольку это довольно очевидно. Менее «волшебный», чем ответ, предложенный Игнасио Васкесом-Абрамсом.

В качестве альтернативы, вы можете сделать это, в котором все еще предполагается, что bool конвертируется в int, но не делается никаких предположений о значении True: ntrue = sum(boollist) / int(True)

kampu
источник
Ваше решение имеет как минимум две проблемы. Во-первых, он страдает от той же проблемы надежности; что вы можете исправить, просто изменив тест на if b. Но, что более важно, вы создаете одноразовый список, требующий, чтобы все значения были в памяти одновременно, и вы не можете использовать его lenс выражением генератора. Лучше избегать такой практики, чтобы решение могло масштабироваться.
Нед Дейли
@Ned Дейли: if bсовершенно неправильно. Было бы правильно, если бы вопрос был об элементах, которые оцениваются как Истина, а не фактические Истинные логические значения. Я понимаю ваше второе замечание. В таком случае есть вариант sum(1 if b is True else 0 for b in boollist).
Кампу
Как я уже отмечал в другом месте, мне не ясно из вопроса, действительно ли OP означает подсчет только объектов типа bool со значением 1 или означает больший и в целом более полезный набор значений, которые оценивают true. Если первое, то проверка личности является правильным подходом, но он также ограничивает. В любом случае, объекты типа bool - довольно странные утки в Python, относительно недавнее дополнение к языку. В любом случае я бы пошел на более простой:sum(1 for b in boollist if b is True)
Нед Дейли