1

My goal is to have python code allowing to detect if a list is sorted or not.

I would like to understand why the following code return True instead of my expected guess False

l = [1, 2, 3, 4, 1, 6, 7, 8, 7]
all(l[i] <= l[i+1] for i in xrange(len(l)-1)) # return "True"

Notes:

  • I'm using python 2.6.4 inside iPython 0.10
  • I use very huge list so I'd prefer to avoid solution of type l == l.sort()

In the way to understand this I already read (and test) info from the main two following post:

EDIT: OK apparently the problem appear inside iPython ONLY, not when using only python command line!

iPython 0.10

In [93]: l = [1, 2, 3, 4, 1, 6, 7, 8, 7]

In [94]: all(l[i] <= l[i+1] for i in xrange(len(l)-1))
Out[94]: True

python 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))
False
Community
  • 1
  • 1
prodev_paris
  • 495
  • 1
  • 4
  • 17
  • @Ajay: can you be more specific? – prodev_paris May 19 '15 at 13:27
  • @musically_ut : which version of python do you use? – prodev_paris May 19 '15 at 13:28
  • @prodev_paris: Indeed I was using `Python 2.7.9`. Python 2.6 also returns `False`. – musically_ut May 19 '15 at 13:29
  • 1
    I'm also getting False on Python 2.6.6, both with the gen exp version and the list comp version. And I get the same results with Python 2.5.5. – PM 2Ring May 19 '15 at 13:29
  • 1
    This may be just splitting hairs, but the code you've shown neither returns nor prints anything. So if you're running this anywhere outside of a REPL, you shouldn't be seeing "True" or anything else. Are you 100% sure that this is the code that's running, and that's the line that's producing output? – Kevin May 19 '15 at 13:34
  • 1
    Seems like an ipython bug to me. The latest version is 3.1. I would try upgrading. – bgm387 May 19 '15 at 13:37
  • @prodev_paris: Can you try a new ipython session and include the full output, including the header information that includes the ipython version and python version? – Bill Lynch May 19 '15 at 13:38
  • 1
    What does `print all.__module__` show? If it's not `__builtin__` you're using it from a different module - probably `numpy`. – Jon Clements May 19 '15 at 13:43
  • @Antti Haapala: This is _pure_ iPython (called from a bash shell) – prodev_paris May 19 '15 at 14:13
  • @Jon Clements `print all.__module__ --------> print(all.__module__) numpy.core.fromnumeric` – prodev_paris May 19 '15 at 14:14

3 Answers3

1

I was able to reproduce a similar problem on my machine. However, after digging, it occurred that the all function was not the built-in function but came from numpy (all.__module__ == 'numpy.core.fromnumeric').

The problem is that you are creating a generator rather than a list. For example:

all(x>5 for x in xrange(3))
# <generator object <genexpr> at 0x1153bf7d0>

all([x>5 for x in xrange(3)])
# False

if all(x>5 for x in xrange(3)):
   print True
else:
   print False
# prints True

if all([x>5 for x in xrange(3)]):
   print True
else:
   print False
# prints False

Simply add [...] to your expression:

all([l[i] <= l[i+1] for i in xrange(len(l)-1)])
# False

If it is the case that you need to create a list, a more efficient solution would be to do a simple for loop:

for i in xrange(len(l)-1):
    if l[i] > l[i+1]:
        result = False
        break
else:
    result = True

If like me, you overrode the built-in all function, you can do del all to recover it. After that, you should have all.__module__ == '__builtin__'. If that's still not the case, just do all = __builtin__.all

Julien Spronck
  • 15,069
  • 4
  • 47
  • 55
  • 4
    That's not a problem - there's no need to create a `list` at all here - the genexp is more than fine – Jon Clements May 19 '15 at 13:30
  • 1
    What version of python are you using to get this output? – Bill Lynch May 19 '15 at 13:34
  • How are you getting `# at 0x1153bf7d0>`? :) You should get and do get `False` – Jon Clements May 19 '15 at 13:35
  • I get the intended results with standard Python 2.7. Are you testing these in something other than the standard Python Shell? – SuperBiasedMan May 19 '15 at 13:35
  • Python 2.7.3 (default, Feb 20 2013, 17:47:37), IPython 0.13.1 – Julien Spronck May 19 '15 at 13:36
  • I just get False in the standard shell. Maybe you're using something other than CPython? – J Richard Snape May 19 '15 at 13:36
  • 2
    @JulienSpronck: It's very likely that you've run `from numpy import *` or `from numpy import all` earlier in your ipython session. – Bill Lynch May 19 '15 at 13:40
  • 1
    This solution wastes memory by creating an extra list. Consider changing it to a loop which breaks as soon as any condition is violated. – musically_ut May 19 '15 at 13:48
  • @BillLynch Thanks for the insight ... let me know if the answer makes more sense now – Julien Spronck May 19 '15 at 14:06
  • 1
    @JulienSpronck: The larger issue is that you and prodev are still seeing different behaviors. prodev claimed that `all(l[i] <= l[i+1] for i in xrange(len(l)-1))` returned `true`, while you (correctly) claim that with numpy it returns a generator. So there's still some difference between your environment, the default environment, and whatever prodev is doing. – Bill Lynch May 19 '15 at 14:08
0

The code you've presented in the question works fine:

Python 2.7

>>> l = [1, 2, 3, 4, 1, 6, 7, 8, 7]
>>> all(l[i] <= l[i+1] for i in xrange(len(l)-1))
False

Python 3.4

We substitute range for xrange...

>>> l = [1, 2, 3, 4, 1, 6, 7, 8, 7]
>>> all(l[i] <= l[i+1] for i in range(len(l)-1))
False

IPython 3.0.0 with Python 2.7.6

In [1]: l = [1, 2, 3, 4, 1, 6, 7, 8, 7]

In [2]: all(l[i] <= l[i+1] for i in xrange(len(l)-1))
Out[2]: False
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
0

Finally it appear that a working solution in iPython 0.10 would be:

In [93]: l = [1, 2, 3, 4, 1, 6, 7, 8, 7]
In [100]: all([l[i] <= l[i+1] for i in xrange(len(l)-1)])
Out[100]: False

EDIT: Or better: use a loop as presented in the accepted answer!

prodev_paris
  • 495
  • 1
  • 4
  • 17
  • 2
    That solution wastes memory by creating an extra list. Consider changing it to a loop which breaks as soon as any condition is violated. – musically_ut May 19 '15 at 13:48
  • @musically_ut You are totally right :) the loop presented by Julien Spronck indeed appears to be a better solution for my situation (old iPython) – prodev_paris May 20 '15 at 14:21