Search code examples
pythonlistor-operatortruthiness

Python OR for list


In Python you can do

print (0 or None or False or "" or [] or "hello" or None or "bar")

which will print

hello

Can you do the same with a list? I.e. is there a Python function foo so that the following will also print hello?

print (foo([0, None, False, "", [], "hello", None, "bar"]))

Note that bar is not printed.


Solution

  • You can use next(filter(None, ...)) or next(filter(bool, ...)) to find the first truthy value from a list:

    def foo(l):
        return next(filter(None, l))
    

    The filter() function takes both a filter function, and an iterable, and returns an iterator that of the values from the iterable that pass the filter.

    But when you set the filter function to None, then it is essentially the same thing as using bool as the filter function, so only values that are true are allowed through. The next() function then gives you the first such value.

    Demo:

    >>> def foo(l):
    ...     return next(filter(None, l))
    ...
    >>> print(foo([0, None, False, "", [], "hello", None, "bar"]))
    hello
    

    You may want to add the last value in l as a default for the next() call, in case there are only falsey values; v1 or v2 or v3 or v4 would at least produce v4 if none of the values are truthy, so the following does too:

    def foo(l):
        return next(filter(None, l), l[-1])
    

    Using filter(None, ...) is a fraction faster than filter(bool, ...) because the filter.__next__ implementation tests for None before it tests for bool; this speed difference is very small and barely measurable (within a margin of error):

    >>> import timeit
    >>> import random
    >>> t = [random.choice([True, False]) for _ in range(10 ** 6)]
    >>> for ff in ('bool', 'None'):
    ...     count, total = timeit.Timer(f'deque(filter({ff}, t), maxlen=0)', 'from collections import deque; from __main__ import t').autorange()
    ...     print(f"{ff}: {total / count * 1000:8.4f} ms")
    ...
    bool:  98.9971 ms
    None:  95.7907 ms