189

Is there a pythonic way to check if a list is already sorted in ASC or DESC

listtimestamps = [1, 2, 3, 5, 6, 7]

something like isttimestamps.isSorted() that returns True or False.

I want to input a list of timestamps for some messages and check if the the transactions appeared in the correct order.

nbro
  • 15,395
  • 32
  • 113
  • 196
anijhaw
  • 8,954
  • 7
  • 35
  • 36

27 Answers27

276

Here is a one liner:

all(l[i] <= l[i+1] for i in range(len(l) - 1))

If using Python 2, use xrange instead of range.

For reverse=True, use >= instead of <=.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
Wai Yip Tung
  • 18,106
  • 10
  • 43
  • 47
  • 4
    that's nice. You might want to wrap it in a function so your can pass a `key` function to use. `key=lambda x, y: x < y` makes a good default. – aaronasterling Sep 20 '10 at 20:35
  • 4
    A combo of a couple of the solutions: `def isSorted(x, key = lambda x: x): return all([key(x[i]) <= key(x[i + 1]) for i in xrange(len(x) - 1)])` – eacousineau Sep 27 '11 at 23:26
  • 2
    @aaronasterling: `operator.le` should be faster than the lambda – Marian Oct 23 '12 at 19:47
  • This does not work for me (python --version = 2.6.4) `l = [1, 2, 3, 4, 1, 6, 7, 8, 7] all(l[i] <= l[i+1] for i in xrange(len(l)-1))` print as result: `True` – prodev_paris May 19 '15 at 09:59
  • @prodev_paris you must have done something wrong, it works for me, as it should. – Eloff May 22 '15 at 16:20
  • @Eloff It was due to iPython module. see http://stackoverflow.com/a/30327058/4716013 Thanks anyway for responding :) – prodev_paris May 26 '15 at 10:21
  • @aaronasterling any idea why `def is_sorted(x, key = lambda x, y: x <= y): return all(key(x[i], x[i + i]) for i in xrange(len(x) - 1))` gives me a _list index out of range_ error? – arcticmatt Jun 15 '15 at 06:01
  • Is there a reason to use the for loop over just plain indexing methods? i.e. `np.all(a[1:]>=a[:-1])` EDIT: oops, this isn't a numpy-specific question. It does have a simpler numpy-specific answer though! – Daniel F Nov 29 '16 at 11:04
  • 2
    Looks like Python 3.x does not have `xrange` anymore, just use `range`. I get `NameError: name 'xrange' is not defined` when I run that code. I switched it to just use `range` instead of `xrange` and that works fine. See: https://stackoverflow.com/questions/15014310/why-is-there-no-xrange-function-in-python3 – Cale Sweeney Jan 05 '18 at 01:27
  • this is way slower then `sorted(l)==l` when the list is sorted, it is faster in the other cases and pointless if you are going to check to then sort. – olivecoder Apr 04 '18 at 13:51
115

I would just use

if sorted(lst) == lst:
    # code here

unless it's a very big list in which case you might want to create a custom function.

if you are just going to sort it if it's not sorted, then forget the check and sort it.

lst.sort()

and don't think about it too much.

if you want a custom function, you can do something like

def is_sorted(lst, key=lambda x: x):
    for i, el in enumerate(lst[1:]):
        if key(el) < key(lst[i]): # i is the index of the previous element
            return False
    return True

This will be O(n) if the list is already sorted though (and O(n) in a for loop at that!) so, unless you expect it to be not sorted (and fairly random) most of the time, I would, again, just sort the list.

dimo414
  • 47,227
  • 18
  • 148
  • 244
aaronasterling
  • 68,820
  • 20
  • 127
  • 125
  • 14
    If that's what you're going to do, you might as well just say: lst.sort() without the conditional check ;-) – SapphireSun Sep 20 '10 at 20:20
  • 7
    thats nlogn right there is a clearly faster way in O(n) using a simple for loop. – anijhaw Sep 20 '10 at 20:22
  • 1
    @SapphireSun. That's what I said ;) – aaronasterling Sep 20 '10 at 20:24
  • @anijhaw, See the update I made while you were leaving the comment. checking is O(n) and sorting is O(nlgn). is it better to incur an O(n) cost to just turn around and add O(nlgn) or just take the cost of sorting a sorted list wich is (i believe) O(n) for timsort. – aaronasterling Sep 20 '10 at 20:26
  • @ Aaron:Check the Edit to the original question, – anijhaw Sep 20 '10 at 23:52
  • This seems more straightforward and has fewer python bytecode instructions: `def is_sorted(lst, key=lambda x, y: x <= y): return all(key(lst[i], el) for i, el in enumerate(lst[1:]))` – hughdbrown Oct 12 '12 at 02:11
  • Your custom function has a bug: is_sorted([1,0]) -> True – Alexandre Vassalotti Aug 07 '13 at 23:24
  • ``is_sorted`` will be O(n), disregarding whether the list is already sorted or not. – liborm Oct 15 '14 at 13:54
  • Even though this thread is very old, I would like to mention that this is the only solution I have found so far on this thread which really answers the question. Every other answer is just feasible for ascending order but not descending order in the arrays as asked! Also no one is accounting for precision... – wagnerpeer Jan 18 '18 at 07:38
  • @hughdbrown This name `key` is ambiguous. That's `operator.le`. – InQβ Sep 17 '18 at 05:28
56

This iterator form is 10-15% faster than using integer indexing:

# python2 only
if str is bytes:
    from itertools import izip as zip

def is_sorted(l):
    return all(a <= b for a, b in zip(l, l[1:]))
maksim
  • 806
  • 2
  • 9
  • 16
PaulMcG
  • 62,419
  • 16
  • 94
  • 130
  • I don't see significant difference on my machine https://gist.github.com/735259 The modified #7 variant from @Nathan Farrington's answer is 2x faster http://stackoverflow.com/questions/3755136/pythonic-way-to-check-if-a-list-is-sorted-or-not/4404056#4404056 – jfs Jan 17 '11 at 09:06
  • This will only work for 'indexable' containers like a list, in which case two new lists are created with the slicing. For general iterators, I prefer [Alexandre's solution](http://stackoverflow.com/a/17224104). – Bas Swinckels May 08 '16 at 11:24
  • 1
    Elegant answer, you can use `izip` and `islice` from itertools to make it faster. – Elmex80s Jan 09 '18 at 10:26
  • @jfs: the "#7 variant from Nathan Farrington's" is wrong. it just does not do what it is supposed to do and that is why it is faster. see my comment there. – olivecoder Apr 04 '18 at 13:41
  • @olivecoder read my comments there from 2011. They point out that the solutions are wrong and how to fix them. The correct fixed variant is still faster on CPython (explicit loop vs. generator expression. The former wins). Here's [more details (text in Russian. You can run the microbenchmarks yourself to make sure](https://ru.stackoverflow.com/a/568193/23044) – jfs Apr 04 '18 at 14:33
  • 1
    You can simplify your solution to zip(l, l[1:]), because zip stops when the shortest argument is exhausted – Gelineau May 09 '18 at 09:45
24

A beautiful way to implement this is to use the imap function from itertools:

from itertools import imap, tee
import operator

def is_sorted(iterable, compare=operator.le):
  a, b = tee(iterable)
  next(b, None)
  return all(imap(compare, a, b))

This implementation is fast and works on any iterables.

Alexandre Vassalotti
  • 1,895
  • 2
  • 15
  • 14
11

I'd do this (stealing from a lot of answers here [Aaron Sterling, Wai Yip Tung, sorta from Paul McGuire] and mostly Armin Ronacher):

from itertools import tee, izip

def pairwise(iterable):
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

def is_sorted(iterable, key=lambda a, b: a <= b):
    return all(key(a, b) for a, b in pairwise(iterable))

One nice thing: you don't have to realize the second iterable for the series (unlike with a list slice).

banbh
  • 1,331
  • 1
  • 13
  • 31
hughdbrown
  • 47,733
  • 20
  • 85
  • 108
  • 3
    misleading name `key`. `key` should be used to turn items into comparable values. – InQβ Sep 17 '18 at 05:52
  • From Pythn 3.10, this can be use [itertools.pairwise](https://docs.python.org/3/library/itertools.html#itertools.pairwise). – greybeard Sep 27 '22 at 05:14
7

I ran a benchmark and sorted(lst, reverse=True) == lst was the fastest for long lists, and all(l[i] >= l[i+1] for i in xrange(len(l)-1)) was the fastest for short lists. These benchmarks were run on a MacBook Pro 2010 13" (Core2 Duo 2.66GHz, 4GB 1067MHz DDR3 RAM, Mac OS X 10.6.5).

UPDATE: I revised the script so that you can run it directly on your own system. The previous version had bugs. Also, I have added both sorted and unsorted inputs.

  • Best for short sorted lists: all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • Best for long sorted lists: sorted(l, reverse=True) == l
  • Best for short unsorted lists: all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • Best for long unsorted lists: all(l[i] >= l[i+1] for i in xrange(len(l)-1))

So in most cases there is a clear winner.

UPDATE: aaronasterling's answers (#6 and #7) are actually the fastest in all cases. #7 is the fastest because it doesn't have a layer of indirection to lookup the key.

#!/usr/bin/env python

import itertools
import time

def benchmark(f, *args):
    t1 = time.time()
    for i in xrange(1000000):
        f(*args)
    t2 = time.time()
    return t2-t1

L1 = range(4, 0, -1)
L2 = range(100, 0, -1)
L3 = range(0, 4)
L4 = range(0, 100)

# 1.
def isNonIncreasing(l, key=lambda x,y: x >= y): 
    return all(key(l[i],l[i+1]) for i in xrange(len(l)-1))
print benchmark(isNonIncreasing, L1) # 2.47253704071
print benchmark(isNonIncreasing, L2) # 34.5398209095
print benchmark(isNonIncreasing, L3) # 2.1916718483
print benchmark(isNonIncreasing, L4) # 2.19576501846

# 2.
def isNonIncreasing(l):
    return all(l[i] >= l[i+1] for i in xrange(len(l)-1))
print benchmark(isNonIncreasing, L1) # 1.86919999123
print benchmark(isNonIncreasing, L2) # 21.8603689671
print benchmark(isNonIncreasing, L3) # 1.95684289932
print benchmark(isNonIncreasing, L4) # 1.95272517204

# 3.
def isNonIncreasing(l, key=lambda x,y: x >= y): 
    return all(key(a,b) for (a,b) in itertools.izip(l[:-1],l[1:]))
print benchmark(isNonIncreasing, L1) # 2.65468883514
print benchmark(isNonIncreasing, L2) # 29.7504849434
print benchmark(isNonIncreasing, L3) # 2.78062295914
print benchmark(isNonIncreasing, L4) # 3.73436689377

# 4.
def isNonIncreasing(l):
    return all(a >= b for (a,b) in itertools.izip(l[:-1],l[1:]))
print benchmark(isNonIncreasing, L1) # 2.06947803497
print benchmark(isNonIncreasing, L2) # 15.6351969242
print benchmark(isNonIncreasing, L3) # 2.45671010017
print benchmark(isNonIncreasing, L4) # 3.48461818695

# 5.
def isNonIncreasing(l):
    return sorted(l, reverse=True) == l
print benchmark(isNonIncreasing, L1) # 2.01579380035
print benchmark(isNonIncreasing, L2) # 5.44593787193
print benchmark(isNonIncreasing, L3) # 2.01813793182
print benchmark(isNonIncreasing, L4) # 4.97615599632

# 6.
def isNonIncreasing(l, key=lambda x, y: x >= y): 
    for i, el in enumerate(l[1:]):
        if key(el, l[i-1]):
            return False
    return True
print benchmark(isNonIncreasing, L1) # 1.06842684746
print benchmark(isNonIncreasing, L2) # 1.67291283607
print benchmark(isNonIncreasing, L3) # 1.39491200447
print benchmark(isNonIncreasing, L4) # 1.80557894707

# 7.
def isNonIncreasing(l):
    for i, el in enumerate(l[1:]):
        if el >= l[i-1]:
            return False
    return True
print benchmark(isNonIncreasing, L1) # 0.883186101913
print benchmark(isNonIncreasing, L2) # 1.42852401733
print benchmark(isNonIncreasing, L3) # 1.09229516983
print benchmark(isNonIncreasing, L4) # 1.59502696991
greybeard
  • 2,249
  • 8
  • 30
  • 66
Nathan Farrington
  • 1,890
  • 1
  • 17
  • 27
  • 2
    You're bench mark is testing worst case for the generator expression forms and the best case for my solution. You might want to test against a non-sorted list as well. Then you will see that the, unless you expect the list to be sorted most of the time, the generator expression is better. – aaronasterling Dec 09 '10 at 23:14
  • @aaronsterling, I have updated the script to have both sorted and unsorted inputs. – Nathan Farrington Dec 09 '10 at 23:41
  • All functions with `enumerate` are incorrect. `enumerate(l[1:])` should be replaced by `enumerate(l[1:], 1)` – jfs Jan 17 '11 at 08:04
  • 1
    instead of replacing `enumerate(l[1:])` by `enumerate(l[1:], 1)` you could replace `l[i-1]` by `l[i]`. – jfs Jan 17 '11 at 08:28
  • If you add random input e.g., `L5=range(100); random.shuffle(L5)` then #5 is comparatively slow. In this case the modified #7 is faster overall http://codepad.org/xmWPxHQY – jfs Jan 17 '11 at 08:52
  • `isNonIncreasing` actually returns whether the sequence is *strictly descending*. – jfs Jan 17 '11 at 08:55
  • #7 is faster because it is wrong. if the list is in ascending order it returns always on the first iteration as l[1] >= l[-1]. if the list is is descending order it returns on the second iteration as l[2] >= l[0]. so, it just doesn't do the work. – olivecoder Apr 04 '18 at 13:31
6

Starting in Python 3.10, the new pairwise function provides a way to slide through pairs of consecutive elements, and thus find if all of these pairs satisfy the same predicate of ordering:

from itertools import pairwise

all(x <= y for x, y in pairwise([1, 2, 3, 5, 6, 7]))
# True

The intermediate result of pairwise:

pairwise([1, 2, 3, 5, 6, 7])
# [(1, 2), (2, 3), (3, 5), (5, 6), (6, 7)]
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
5

As I don't see this option above I will add it to all the answers. Let denote the list by l, then:

import numpy as np

# Trasform the list to a numpy array
x = np.array(l)

# check if ascendent sorted:
all(x[:-1] <= x[1:])

# check if descendent sorted:
all(x[:-1] >= x[1:])
FBruzzesi
  • 6,385
  • 3
  • 15
  • 37
  • 2
    Observing the absence of function definitions and absence of explicit loop statements, I consider this answer the most "pythonic" one. It is also not allocating memory nor copying data, due to the way Numpy handles array views. – Fábio Pakk Selmi-Dei Apr 24 '22 at 16:14
  • @FábioPakkSelmi-Dei I would not agree on the "not allocating memory": (1) if you have a list, `np.array(l)` will produce a **new** array thereby allocating new memory for `x`; (2) even if you start from a NumPy array, the `x[:-1] <= x[1:]` statement will result in a new boolean NumPy array the size of the input (minus 1). So all in all, you would need roughly 3 times the memory of the original input, if that is a list. – norok2 Aug 11 '22 at 08:57
4

I use this one-liner based on numpy.diff():

def issorted(x):
    """Check if x is sorted"""
    return (numpy.diff(x) >= 0).all() # is diff between all consecutive entries >= 0?

I haven't really timed it against any other method, but I assume it's faster than any pure Python method, especially for large n, since the loop in numpy.diff (probably) runs directly in C (n-1 subtractions followed by n-1 comparisons).

However, you need to be careful if x is an unsigned int, which might cause silent integer underflow in numpy.diff(), resulting in a false positive. Here's a modified version:

def issorted(x):
    """Check if x is sorted"""
    try:
        if x.dtype.kind == 'u':
            # x is unsigned int array, risk of int underflow in np.diff
            x = numpy.int64(x)
    except AttributeError:
        pass # no dtype, not an array
    return (numpy.diff(x) >= 0).all()
Martin Spacek
  • 2,921
  • 1
  • 15
  • 9
  • This is actually pretty slow for any large sequence, presumably because it computes the diff for the entire sequence. It doesn't work lazily. The various pure Python approaches that use lazy evaluation were over 10x faster in my testing. – Asclepius Jan 10 '22 at 02:20
4

Lazy

from itertools import tee

def is_sorted(l):
    l1, l2 = tee(l)
    next(l2, None)
    return all(a <= b for a, b in zip(l1, l2))
Asclepius
  • 57,944
  • 17
  • 167
  • 143
Sergey11g
  • 1,207
  • 1
  • 9
  • 11
  • 2
    Absolutelly awesome! Here's is my improvement to make it one-liner - instead of iter() and next() use slicing with the same result: `all(a <= b for a, b in zip(l, l[1:]))` – Matt Warrick Nov 25 '16 at 20:44
  • 3
    @LiborJelinek good, but my version works when `l` is a generator and doesn't support slicing. – Sergey11g Dec 04 '16 at 09:32
4

This is similar to the top answer, but I like it better because it avoids explicit indexing. Assuming your list has the name lst, you can generate
(item, next_item) tuples from your list with zip:

all(x <= y for x,y in zip(lst, lst[1:]))

In Python 3, zip already returns a generator, in Python 2 you can use itertools.izip for better memory efficiency.

Small demo:

>>> lst = [1, 2, 3, 4]
>>> zip(lst, lst[1:])
[(1, 2), (2, 3), (3, 4)]
>>> all(x <= y for x,y in zip(lst, lst[1:]))
True
>>> 
>>> lst = [1, 2, 3, 2]
>>> zip(lst, lst[1:])
[(1, 2), (2, 3), (3, 2)]
>>> all(x <= y for x,y in zip(lst, lst[1:]))
False

The last one fails when the tuple (3, 2) is evaluated.

Bonus: checking finite (!) generators which cannot be indexed:

>>> def gen1():
...     yield 1
...     yield 2
...     yield 3
...     yield 4
...     
>>> def gen2():
...     yield 1
...     yield 2
...     yield 4
...     yield 3
... 
>>> g1_1 = gen1()
>>> g1_2 = gen1()
>>> next(g1_2)
1
>>> all(x <= y for x,y in zip(g1_1, g1_2))
True
>>>
>>> g2_1 = gen2()
>>> g2_2 = gen2()
>>> next(g2_2)
1
>>> all(x <= y for x,y in zip(g2_1, g2_2))
False

Make sure to use itertools.izip here if you are using Python 2, otherwise you would defeat the purpose of not having to create lists from the generators.

timgeb
  • 76,762
  • 20
  • 123
  • 145
  • 2
    You can even use `islice` to optimize for slicing. Also in the itertools module. `all(x <= y for x, y in izip(lst, islice(lst, 1)))`. – Elmex80s Jan 09 '18 at 10:27
  • It would be more useful to show hot to test on the same generator (`itertools.tee()`?) rather than on two separate one. – norok2 Aug 11 '22 at 08:51
4

The third-party package method more_itertools.is_sorted hasn't been mentioned yet:

import more_itertools

ls = [1, 4, 2]

print(more_itertools.is_sorted(ls))

ls2 = ["ab", "c", "def"]

print(more_itertools.is_sorted(ls2, key=len))
Asclepius
  • 57,944
  • 17
  • 167
  • 143
Zane Dufour
  • 830
  • 1
  • 9
  • 19
3

As noted by @aaronsterling the following solution is the shortest and seems fastest when the array is sorted and not too small: def is_sorted(lst): return (sorted(lst) == lst)

If most of the time the array is not sorted, it would be desirable to use a solution that does not scan the entire array and returns False as soon as an unsorted prefix is discovered. Following is the fastest solution I could find, it is not particularly elegant:

def is_sorted(lst):
    it = iter(lst)
    try:
        prev = next(it)
    except StopIteration:
        return True
    for x in it:
        if prev > x:  # For reverse, use <
            return False
        prev = x
    return True

Using Nathan Farrington's benchmark, this achieves better runtime than using sorted(lst) in all cases except when running on the large sorted list.

Here are the benchmark results on my computer.

sorted(lst)==lst solution

  • L1: 1.23838591576
  • L2: 4.19063091278
  • L3: 1.17996287346
  • L4: 4.68399500847

Second solution:

  • L1: 0.81095790863
  • L2: 0.802397012711
  • L3: 1.06135106087
  • L4: 8.82761001587
Asclepius
  • 57,944
  • 17
  • 167
  • 143
Amit Moscovich
  • 2,858
  • 1
  • 21
  • 12
3

Although I don't think there is a guarantee for that the sorted built-in calls its cmp function with i+1, i, it does seem to do so for CPython.

So you could do something like:

def my_cmp(x, y):
   cmpval = cmp(x, y)
   if cmpval < 0:
      raise ValueError
   return cmpval

def is_sorted(lst):
   try:
      sorted(lst, cmp=my_cmp)
      return True
   except ValueError:
      return False

print is_sorted([1,2,3,5,6,7])
print is_sorted([1,2,5,3,6,7])

Or this way (without if statements -> EAFP gone wrong? ;-) ):

def my_cmp(x, y):
   assert(x >= y)
   return -1

def is_sorted(lst):
   try:
      sorted(lst, cmp=my_cmp)
      return True
   except AssertionError:
      return False
Anthon
  • 69,918
  • 32
  • 186
  • 246
  • This one is interesting because it lifts the looping to C from within Python. However, the use of exceptions and function calls may compensate for that. Have you timed it? – norok2 Aug 11 '22 at 09:00
  • Not that I remember, but it has been a while. – Anthon Aug 11 '22 at 13:16
3

Just to add another way (even if it requires an additional module): iteration_utilities.all_monotone:

>>> from iteration_utilities import all_monotone
>>> listtimestamps = [1, 2, 3, 5, 6, 7]
>>> all_monotone(listtimestamps)
True

>>> all_monotone([1,2,1])
False

To check for DESC order:

>>> all_monotone(listtimestamps, decreasing=True)
False

>>> all_monotone([3,2,1], decreasing=True)
True

There is also a strict parameter if you need to check for strictly (if successive elements should not be equal) monotonic sequences.

It's not a problem in your case but if your sequences contains nan values then some methods will fail, for example with sorted:

def is_sorted_using_sorted(iterable):
    return sorted(iterable) == iterable

>>> is_sorted_using_sorted([3, float('nan'), 1])  # definitely False, right?
True

>>> all_monotone([3, float('nan'), 1])
False

Note that iteration_utilities.all_monotone performs faster compared to the other solutions mentioned here especially for unsorted inputs (see benchmark).

Asclepius
  • 57,944
  • 17
  • 167
  • 143
MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • This is fast, but why is it measurably slower than [this answer](https://stackoverflow.com/a/10785124/)? – Asclepius Jan 15 '22 at 17:22
  • @Asclepius To which measurements do you refer? I haven't seen a benchmark that includes both answers here and don't have the time this weekend to do one myself. – MSeifert Jan 15 '22 at 18:50
2

Not very Pythonic at all, but we need at least one reduce() answer, right?

def is_sorted(iterable):
    prev_or_inf = lambda prev, i: i if prev <= i else float('inf')
    return reduce(prev_or_inf, iterable, float('-inf')) < float('inf')

The accumulator variable simply stores that last-checked value, and if any value is smaller than the previous value, the accumulator is set to infinity (and thus will still be infinity at the end, since the 'previous value' will always be bigger than the current one).

orlade
  • 2,060
  • 4
  • 24
  • 35
1

SapphireSun is quite right. You can just use lst.sort(). Python's sort implementation (TimSort) check if the list is already sorted. If so sort() will completed in linear time. Sounds like a Pythonic way to ensure a list is sorted ;)

Wai Yip Tung
  • 18,106
  • 10
  • 43
  • 47
  • 23
    Only linear time if the list is, in fact, sorted. If not, there is no short-circuit to skip the actual sorting task, so could be a huge penalty to pay if the list is long. – PaulMcG Sep 20 '10 at 20:57
  • 2
    This is a great answer if your task is "make sure the list is sorted and die if not". Which is pretty common as a sanity check of data that should be sorted for some other reason. Then only the error case is slow. – Ed Avis Mar 08 '19 at 16:36
1

Python 3.6.8

from more_itertools import pairwise

class AssertionHelper:
    @classmethod
    def is_ascending(cls, data: iter) -> bool:
        for a, b in pairwise(data):
            if a > b:
                return False
        return True

    @classmethod
    def is_descending(cls, data: iter) -> bool:
        for a, b in pairwise(data):
            if a < b:
                return False
        return True

    @classmethod
    def is_sorted(cls, data: iter) -> bool:
        return cls.is_ascending(data) or cls.is_descending(data)
>>> AssertionHelper.is_descending((1, 2, 3, 4))
False
>>> AssertionHelper.is_ascending((1, 2, 3, 4))
True
>>> AssertionHelper.is_sorted((1, 2, 3, 4))
True

Chweng Mega
  • 1,598
  • 1
  • 13
  • 22
1

A solution using assignment expressions (added in Python 3.8):

def is_sorted(seq):
    seq_iter = iter(seq)
    cur = next(seq_iter, None)
    return all((prev := cur) <= (cur := nxt) for nxt in seq_iter)

z = list(range(10))
print(z)
print(is_sorted(z))

import random
random.shuffle(z)
print(z)
print(is_sorted(z))

z = []
print(z)
print(is_sorted(z))

Gives:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
True
[1, 7, 5, 9, 4, 0, 8, 3, 2, 6]
False
[]
True
PaulMcG
  • 62,419
  • 16
  • 94
  • 130
  • 2
    Although `prev :=` looks to add clarity, it seems unnecessary. Just `cur <= (cur := nxt)` seems minimally sufficient. And for `reverse=True`, I used `>=` instead of `<=`. – Asclepius Jan 10 '22 at 20:58
1

This approach using Pandas is very slow, but it's noted for completeness.

from typing import Sequence

import pandas as pd

def is_sorted(seq: Sequence, reverse: bool = False) -> bool:
    index = pd.Index(seq)
    if reverse:
        return index.is_monotonic_decreasing
    return index.is_monotonic_increasing
Asclepius
  • 57,944
  • 17
  • 167
  • 143
0

If you want the fastest way for numpy arrays, use numba, which if you use conda should be already installed

The code will be fast because it will be compiled by numba

import numba
@numba.jit
def issorted(vec, ascending=True):
    if len(vec) < 2:
        return True
    if ascending:
        for i in range(1, len(vec)):
            if vec[i-1] > vec[i]:
                return False
        return True
    else:
        for i in range(1, len(vec)):
            if vec[i-1] < vec[i]:
                return False
        return True

and then:

>>> issorted(array([4,9,100]))
>>> True
tal
  • 860
  • 7
  • 19
  • If the input is a Python list, the `numba`-accelerated code does not always perform better than the non-accelerated one. You should at least provide some evidence that it outperforms some other solution (at least under some circumstances) to substantiate your claiming that it will be fast. – norok2 Aug 11 '22 at 09:05
-1

This uses recursion:

 def is_sorted(lst):
    if len(lst) == 1:
       return True
    return lst[0] <= lst[1] and is_sorted(lst[1:])

 some_list = [1,2,3,4]
 print(is_sorted(some_list))

Note that this will raise RuntimeError: maximum recursion depth exceeded for long sequences.

Jay Lee
  • 1,684
  • 1
  • 15
  • 27
Baraa
  • 9
  • 2
  • 1
    Note that this will raise `RuntimeError: maximum recursion depth exceeded` for long lists. Try `any_list = range(1000)`. – timgeb Feb 19 '16 at 00:28
-1
from functools import reduce

# myiterable can be of any iterable type (including list)
isSorted = reduce(lambda r, e: (r[0] and (r[1] or r[2] <= e), False, e), myiterable, (True, True, None))[0]

The derived reduction value is a 3-part tuple of (sortedSoFarFlag, firstTimeFlag, lastElementValue). It initially starts with (True, True, None), which is also used as the result for an empty list (regarded as sorted because there are no out-of-order elements). As it processes each element it calculates new values for the tuple (using previous tuple values with the next elementValue):

[0] (sortedSoFarFlag) evaluates true if: prev_0 is true and (prev_1 is true or prev_2 <= elementValue)
[1] (firstTimeFlag): False
[2] (lastElementValue): elementValue

The final result of the reduction is a tuple of:

[0]: True/False depending on whether the entire list was in sorted order
[1]: True/False depending on whether the list was empty
[2]: the last element value

The first value is the one we're interested in, so we use [0] to grab that from the reduce result.

Mr Weasel
  • 82
  • 5
  • Note that this solution works for any iterable containing element types that can be compared with each other. That includes lists of boolean (checks the False values occur before the True values), lists of numbers, lists of strings (alphabetical order), lists of sets (subsets occur before supersets) etc. – Mr Weasel Jul 23 '19 at 11:13
-1

Try this:

def is_sorted(arr) -> bool:
    for i in range(1, len(arr)):
        if arr[i] < arr[i - 1]:
            return False
    return True
Rustam-Z
  • 113
  • 1
  • 9
-3

How about this one ? Simple and straightforward.

def is_list_sorted(al):

    llength =len(al)


    for i in range (llength):
        if (al[i-1] > al[i]):
            print(al[i])
            print(al[i+1])
            print('Not sorted')
            return -1

    else :
        print('sorted')
        return  true
Zuckerberg
  • 205
  • 6
  • 15
-3

Simplest way:

def isSorted(arr):
  i = 1
  while i < len(arr):
    if(result[i] < result[i - 1]):
      return False
    i += 1
  return True
-5

Definitely works in Python 3 and above for integers or strings:

def tail(t):
    return t[:]

letters = ['a', 'b', 'c', 'd', 'e']
rest = tail(letters)
rest.sort()
if letters == rest:
    print ('Given list is SORTED.')
else:
    print ('List NOT Sorted.')

=====================================================================

Another way of finding if the given list is sorted or not

trees1 = list ([1, 4, 5, 3, 2])
trees2 = list (trees1)
trees2.sort()
if trees1 == trees2:
    print ('trees1 is SORTED')
else:
    print ('Not sorted')
prodev_paris
  • 495
  • 1
  • 4
  • 17
cooldeal
  • 351
  • 3
  • 2