-1

I like to use any() and all() in Python. But sometimes I need a one().

I want to know if only one value or condition in a list is True.

Currently I do it with such a nested ugly if.

# In real world there could be more then just two elements
istrue = [True, False]
isfalse = [True, 'foobar']
isfalse2 = [False, False]

def one(values):
    if values[0] and values[1]:
        return False
    if not values[0] and not values[1]:
        return False
    return True

one(istrue)  # True
one(isfalse)  # False
one(isfalse2)  # False

I assume there is a more pythonic way, isn't it?

buhtz
  • 10,774
  • 18
  • 76
  • 149

3 Answers3

9
sum(map(bool, l)) == 1

This is probably the shortest expression. It turns every item in the list into a boolean, and sums them. A truthy value will count as 1, a falsey value as 0. Thus if the sum is exactly 1, there was exactly one truthy item in it.

If you want the short-circuiting behaviour of all/any, which avoids iterating all items unnecessarily, then something like this:

def one(l):
    truthy = 0
    for i in l:
        truthy += bool(i)
        if truthy > 1:
            return False
    return truthy == 1
deceze
  • 510,633
  • 85
  • 743
  • 889
  • 1
    Considering you are assigning 0 to truthy and short circuit if it's more than 1 you can just return `True` after the loop, no addded value in comparing to 1 (unless I'm missing something). Anyway +1, best answer imo. – Gameplay Feb 28 '23 at 08:55
  • 2
    No, `truthy` might still be `0` after the loop. – deceze Feb 28 '23 at 08:56
  • 1
    Ah, right. Nevermind the above then. – Gameplay Feb 28 '23 at 08:58
5

Convert all elements to boolean and then sum them up:

def one(values):
    return sum(bool(x) for x in values) == 1
ypnos
  • 50,202
  • 14
  • 95
  • 141
1

Yes, there is a more Pythonic way to implement a function that checks if exactly one element in an iterable is True. Here's a more concise implementation using Python's built-in sum() function:

def one(iterable):
    """Return True if exactly one element in the iterable is true."""
    return sum(map(bool, iterable)) == 1
Stephen
  • 635
  • 5
  • 7