HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Checking whether a list is sorted, ascending or descending

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
descendingcheckingsortedlistwhetherascending

Problem

What is the best way to conditionally use an operator? All 3 methods seemed acceptable to me, and the last 2 better.

If you're curious: I've got a list which is unsorted, and many other lists which may or may not contain a smaller selection of sorted indices referencing the unsorted list. Processed data is being identified as lists which contain sorted references.

I've tried an anonymous function...

if reverse:
    list_is_sorted = lambda unsorted, indices:    \
                     all(unsorted[indices[i]] >=  \
                         unsorted[indices[i + 1]] \   
                         for i in xrange(len(indices) - 1)))        
else:
    list_is_sorted = lambda unsorted, indices:    \ 
                     all(unsorted[indices[i]] <=  \
                         unsorted[indices[i + 1]] \   
                         for i in xrange(len(indices) - 1)))
list_is_sorted()


And an evaluated expression and...

if reverse:
    my_operator = '>='
else:
    my_operator = '<='
eval('all(unsorted[indices[i]] %s  \
          unsorted[indices[i + 1]] \
          for i in xrange(len(indices) - 1))' % my_operator)


Assigning an operator like this:

import operator
if reverse:
    my_operator = lambda x, y: operator.ge(x, y)
else:
    my_operator = lambda x, y: operator.le(x, y)
all(my_operator(unsorted[indices[i]], unsorted[indices[i + 1]]) \
    for i in xrange(len(indices) - 1)))

Solution

I'm a little sure if this is well suited for Code Review, but here goes a little analysis:

Using anonymous functions

This doesn't look right as it is repeating too much code, which is a clear code smell. When quickly looking at it, it is unclear what the actual difference is between the two. So this is not a good option.

Using eval

An old saying says "using eval is evil", and you should avoid using eval if possible. Not only does it have an performance hit, but it is also a major source of security flaws, and not readable code.

Defining your own operator

This is by far the nicest solution, as it doesn't repeat code, and it reads the best. However you could simplify it using direct assignment of the operator instead of using a lambda expression, thusly making it to be:

import operator

my_operator = operator.ge if reverse else operator.le
all(my_operator(unsorted[indices[i]], unsorted[indices[i + 1]]) \
    for i in xrange(len(indices) - 1)))


In a function using a pairwise recipe

Or introducing a function, and the pairwise iterator from itertools recipes v2.7:

import operator
import itertools

def is_sorted(iterable, reverse= False):
    """Check if the iterable is sorted, possibly reverse sorted."""

    def pairwise(iterable):
        """s -> (s0,s1), (s1,s2), (s2, s3), ..."""
        a, b = itertools.tee(iterable)
        next(b, None)
        return itertools.izip(a, b)

    my_operator = operator.ge if reverse else operator.le

    return all(my_operator(current_element, next_element)
                   for current_element, next_element in pairwise(iterable))

# Test the function
print is_sorted([1, 2, 3, 4])            # Should be True
print is_sorted([4, 3, 2, 1], True)      # Should be True
print is_sorted([4, 1, 2, 3])            # Will not be True, ever...

Code Snippets

import operator

my_operator = operator.ge if reverse else operator.le
all(my_operator(unsorted[indices[i]], unsorted[indices[i + 1]]) \
    for i in xrange(len(indices) - 1)))
import operator
import itertools

def is_sorted(iterable, reverse= False):
    """Check if the iterable is sorted, possibly reverse sorted."""

    def pairwise(iterable):
        """s -> (s0,s1), (s1,s2), (s2, s3), ..."""
        a, b = itertools.tee(iterable)
        next(b, None)
        return itertools.izip(a, b)

    my_operator = operator.ge if reverse else operator.le

    return all(my_operator(current_element, next_element)
                   for current_element, next_element in pairwise(iterable))

# Test the function
print is_sorted([1, 2, 3, 4])            # Should be True
print is_sorted([4, 3, 2, 1], True)      # Should be True
print is_sorted([4, 1, 2, 3])            # Will not be True, ever...

Context

StackExchange Code Review Q#107213, answer score: 8

Revisions (0)

No revisions yet.