如何检查可迭代对象中是否恰好有一个值为True?

3

有没有一种简洁易读的方法来检查可迭代对象中的所有元素是否都为True(虽然这与我的问题无关,但可以假设所有值都是布尔值)?我想到了以下方法:

any(it) and not reduce(lambda x, y: x and y, it)

但我认为使用reduce使其有些难以理解,而且我不认为它有效:

In [1]: a=[True, True, False]

In [7]: any(a) and not reduce(lambda x, y: x and y, a)
Out[7]: True

有更易读的方式吗?

更新: 我发现了上面表达式中的错误。reduce()需要在看到True时停止而不是继续。

3个回答

9

虽然你的标题与问题本身不符,但我会回答标题。

你可以对布尔值进行求和。检查它是否等于1(或任何你想要的值):

>>> a = [True, True, False]
>>> sum(a)
2
>>> b = ['hey', '', 'a string']
>>> sum(map(bool,b))
2

我最喜欢这个答案。 - scorpiodawg

5

您可以使用count来完成:

>>> a=[True, True, False]
>>> if a.count(True) == 1:
...     print 'Hello'
... else:
...     print 'Sorry'
Sorry

示例

>>> [True, False].count(True) == 1
True

>>> [True, True, False].count(True) == 1
False

>>> [True, True, False].count(False) == 1
True

有趣。如果元素并非全部明确为布尔值,这是否有效? - scorpiodawg
@scorpiodawg,他们还能是什么? - sshashank124
返回布尔值的lambda表达式怎么办? - scorpiodawg
@scorpiodawg,是的。Lambda会返回一个布尔列表,然后您可以进行检查。 - sshashank124

0

因此,这个的一般格式大致是这样的:

test = [True, True, False]
if len([x for x in test if x]) == 1:
    # Do something

当然,上面只是测试x是否为布尔值True,但你可以放置任何类型的比较。

你可能会说,这不是很低效吗?实际上并不是,如果你确实想要恰好N个项目-你必须检查它们所有的内容,以查看是否还有另一个True潜藏在其中。

对于“N个或更多”项目的情况,你可以有点(滥用)生成器来完成这个操作:

from itertools import islice
result = True
g = (x for x in test if x)
if len(list(islice(g, 2))) == 2: 
    # do something    

这是一种捷径,因为它会在看到项目数量后立即停止,而不会通过生成器继续走下去。如果您想要使用此形式进行精确计数,则它比列表形式具有小优势:

if len(list(islice(g, 2))) == 2 and not any(g):
    # do something 

为什么这样做有一点优势呢?在传递的情况下,我们仍然必须查看每个其他项,以确保列表中恰好有2个“True”。但是在失败的情况下,只要我们看到另一个“True”,“any”就会快捷方式,您就不必遍历列表的其余部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接