7

In newer Python, I am able to use the sorted function and easily sort out a list of strings according to their last few chars as such:

lots_list = ['anything']

print sorted(lots_list, key=returnlastchar)

def returnlastchar(s):     
    return s[10:] 

How can I implement the above to lots_list.sort() in older Python (2.3)?

" Error: When I tried using sorted(), the global name sorted is not defined. "

Georgy
  • 12,464
  • 7
  • 65
  • 73
Poker Prof
  • 169
  • 5
  • 15
  • There are two separate questions here: replacing `sorted` (which was introduced in 2.4), and replacing the `key` argument. The first is trivial, and the answers here only addressed it incidentally: if you don't have "make a sorted copy" but only have "sort in-place", then you can emulate it by "make a copy" and then "sort the copy in-place". The interesting part is handling the key function. – Karl Knechtel Aug 14 '22 at 18:18
  • As a side note, 2.3 was released [in july 2003](https://peps.python.org/pep-0283/), with bug fixes [until 2005](https://www.python.org/downloads/release/python-235/). It was long out of date when this question was asked; it was in fact asked on the second anniversary of the release of 2.7. – Karl Knechtel Aug 14 '22 at 18:24
  • This is something like the reverse of [How to use a custom comparison function in Python 3?](https://stackoverflow.com/questions/2531952/). – Karl Knechtel Aug 14 '22 at 18:32

4 Answers4

8

The Schwartzian transform is usually more efficient than using the cmp argument (This is what newer versions of Python do when using the key argument)

lots_list=['anything']

def returnlastchar(s):     
    return s[10:] 

decorated = [(returnlastchar(s), s) for s in lots_list]
decorated.sort()
lots_list = [x[1] for x in decorated]
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
6

I don't have python 2.3 on hand, however, according to this post Sorting a list of lists by item frequency in Python 2.3 http://docs.python.org/release/2.3/lib/typesseq-mutable.html this method should also works for you.

def mycmp(a, b):
    return cmp(a[10:], b[10:])

lots_list.sort(mycmp)
Community
  • 1
  • 1
lucemia
  • 6,349
  • 5
  • 42
  • 75
1

It's not hard to write you're own version of sorted. Here is a drop-in replacement (excluding the cmp paramenter):

def _count():
    i = 0
    while 1:
        yield i
        i += 1

def sorted(iterable, key=None, reverse=False):
    'Drop-in replacement for the sorted() built-in function (excluding cmp())'
    seq = list(iterable)
    if reverse:
        seq.reverse()
    if key is not None:
        seq = zip(map(key, seq), _count(), seq)
    seq.sort()
    if key is not None:
        seq = map(lambda decorated: decorated[2], seq)
    if reverse:
        seq.reverse()
    return seq
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
0

You can write your own sorted() like so:

try:
    sorted
except NameError:
    def sorted(seq, key=None):
        lst = list(seq)  # get copy of list
        if key is not None:
            def my_cmp(a, b):
                return cmp(key(a), key(b))
        else:
            my_cmp = cmp
        lst.sort(my_cmp)
        return lst

This will only define your new sorted() if there is no built-in sorted(). First, we try to evaluate the name sorted and if we get a NameError we define our own. I'm using map(None, seq) as a fast way to make a new list out of the values of seq.

Or, if we want to use the Schwartzian Transform for maximum efficiency as suggested by @gnibbler:

try:
    sorted
except NameError:
    import operator as op
    def sorted(seq, key=None):
        if key is not None:
            lst = [(key(x), x) for x in seq]
            lst.sort()
            return map(lambda x: x[1], lst)
        else:
            lst = list(seq) # get list from sequence
            lst.sort()
            return lst
steveha
  • 74,789
  • 21
  • 92
  • 117