Question

Is there an elegant, readable way to check if all the elements in an iterable it resolve to True (you may assume all values are boolean though that's not relevant to my question)? I came up with:

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

but I think the reduce makes it somewhat confusing to understand plus I don't think it works:

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

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

Are there more readable ways?

Update: I realized the error in my expression above. reduce() needs to stop when it sees a True and not continue.

Was it helpful?

Solution

Your title disagrees with the body of your question, but I'll answer the title.

You can sum boolean values. Check if it's equal to 1 (or whatever value you'd like):

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

OTHER TIPS

You can do it using count:

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

Examples

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

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

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

So, the general format for this is something like this:

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

Of course, the above is just testing if x is boolean True, but you could put any kind of comparison there.

You might say, but isn't that inefficient? Not really, if you really want exactly N items - you'd have to check them all anyways to see if there is another True lurking in there.

For the case where it's 'N or more' items, you can kind of (ab)use generators to do this:

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

This is a bit of a shortcut, since it will stop as soon as it sees the number of items and not walk farther through the generator. If you wanted to use this form for an exact count, it has a small advantage over the list form:

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

Why does this have a small advantage? In the passing case, we still have to look through every other item to make sure there are exactly 2 Trues in the list. But in the failing case, as soon as we see another True, the any will shortcut and you won't walk through the rest of the list.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top