计算 Python 列表中真布尔值的个数

我有一个布尔型的列表:

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

并且我正在寻找一种方法来计算列表中 True的数量(因此在上面的例子中,我希望返回值是 3)我已经找到了查找特定元素出现次数的示例,但是由于我使用的是布尔型,是否有更有效的方法来做到这一点呢?我在想一些类似于 all或者 any的东西。

218076 次浏览

True等于 1

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

你可以使用 sum():

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

如果您只关心常数 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

附注: 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

我更喜欢 len([b for b in boollist if b is True])(或者生成器表达式等价物) ,因为它非常简单明了。没有 Ignacio Vazquez-Abrams 提出的答案那么“神奇”。

或者,您可以这样做,它仍然假设 bool 可以转换为 int,但是不假设 True 的值: ntrue = sum(boollist) / int(True)

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)

首先运行 bool是比较安全的,这很容易做到:

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

然后,您将把 Python 认为正确或错误的所有内容都捕获到适当的桶中:

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

为了完整起见(sum通常更好) ,我想提到的是我们也可以使用 filter来获得真实值。在通常情况下,filter接受一个函数作为第一个参数,但是如果传递给它 None,它将筛选所有“ true”值。这个特性有些令人惊讶,但是已经有很好的文档说明,并且可以在 Python2和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

在阅读了所有关于这个问题的答案和评论之后,我想做一个小实验。

我生成了50,000个随机布尔值,并对它们调用 sumcount

以下是我的结果:

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

如你所见,countsum快3倍。所以我建议使用 count,就像我在 count_it中所做的那样。

Python 版本: 3.6.7
CPU 核心: 4
RAM 大小: 16GB
操作系统: Ubuntu 18.04.1 LTS