Your function can be reduced to this:
def checker(nums):
return all(i <= j for i, j in zip(nums, nums[1:]))
Note the following:
zip
loops through its arguments in parallel, i.e. nums[0]
& nums[1]
are retrieved, then nums[1]
& nums[2]
etc.
i <= j
performs the actual comparison.
- The generator expression denoted by parentheses
()
ensures that each value of the condition, i.e. True
or False
is extracted one at a time. This is called lazy evaluation.
all
simply checks all the values are True
. Again, this is lazy. If one of the values extracted lazily from the generator expression is False
, it short-circuits and returns False
.
Alternatives
To avoid the expense of building a list for the second argument of zip
, you can use itertools.islice
. This option is particularly useful when your input is an iterator, i.e. it cannot be sliced like a list
.
from itertools import islice
def checker(nums):
return all(i <= j for i, j in zip(nums, islice(nums, 1, None)))
Another iterator-friendly option is to use the itertools
pairwise
recipe, also available via 3rd party more_itertools.pairwise
:
# from more_itertools import pairwise # 3rd party library alternative
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
def checker(nums):
return all(i <= j for i, j in pairwise(nums))
Another alternative is to use a functional approach instead of a comprehension:
from operator import le
def checker_functional(nums):
return all(map(le, nums, nums[1:]))