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