The Python Oracle

How to use the IF ALL statement in Python

This video explains
How to use the IF ALL statement in Python

--

Become part of the top 3% of the developers by applying to Toptal
https://topt.al/25cXVn

--

Music by Eric Matyas
https://www.soundimage.org
Track title: Quirky Dreamscape Looping

--

Chapters
00:00 Question
00:52 Accepted answer (Score 32)
02:43 Answer 2 (Score 10)
03:04 Answer 3 (Score 3)
03:39 Thank you

--

Full question
https://stackoverflow.com/questions/4886...

Accepted answer links:
[zip]: https://docs.python.org/3/library/functi...
[generator expression]: https://docs.python.org/3/reference/expr...
[all]: https://docs.python.org/3/library/functi...
[itertools.islice]: https://docs.python.org/3/library/iterto...
[itertools]: https://docs.python.org/3/library/iterto...
[more_itertools.pairwise]: https://more-itertools.readthedocs.io/en...

Answer 3 links:
[more_itertools.windowed]: http://more-itertools.readthedocs.io/en/...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #list #sorting #ifstatement #conditionalstatements

#avk47



ACCEPTED ANSWER

Score 32


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:]))



ANSWER 2

Score 9


Your code can in fact be reduced to checking if nums is sorted, e.g.

def checker(nums):
    return sorted(nums) == nums

This does exactly what you expect, e.g.

>>> checker([1, 1, 2, 2, 3])
True
>>> checker([1, 1, 2, 2, 1])
False



ANSWER 3

Score 3


Similar solution to @jp_data_analysis using more_itertools.windowed

>>> from more_itertools import windowed
>>> nums = [1, 1, 2, 2, 3]
>>> all(i <= j for i, j in windowed(nums, 2))
True

And for scientific purposes (not recommended code), here is a more functional approach

>>> from operator import le
>>> from itertools import starmap
>>> all(starmap(le, windowed(nums, 2)))
True