Re: sort() method

Tim Peters (tim@ksr.com)
Wed, 15 Jul 92 19:02:22 -0400

> ...
> However the speed of my Python scripts are far from of the perl ones.

Depends on what you're doing ... e.g., at present, Perl is incomparably
faster at string searching, Python is incomparably faster at big-integer
arithmetic ...

> ...
> One of the problems I've encountered is that I frequently used the Perl
> feature which allows the user to give his own comparing function as a
> parameter to the sort routine. I couldn't find anything similar in
> Python and therefore the equivalent Python code segment became more
> complicated.
>
> Is there any Python style way to work around this problem?

Note that Python does lexicographic sorting on tuples -- that is, the
first element of a tuple is used as the primary key, the second element
is the secondary key, and so on. So, e.g.,

>>> a = [ ('a',9), ('b',2), ('aa',3), ('b',0) ]
>>> a.sort()
>>> a
[('a', 9), ('aa', 3), ('b', 0), ('b', 2)]
>>>

Note that the list is sorted by the first tuple component (the string),
and that "ties" are resolved by sorting on the second tuple component
(the integer -- that's why the two "('b',...)" entries were swapped).

Lexicographic sorting is powerful, so the usual trick in Python is to
create your data this way to begin with, or to create a temp list,
embedding your data in tuples of which the first component is of a
simple type (int or string) and whose values reflect the ordering you
want.

But that is clumsy, if you need to do it often. If, e.g., I want to
sort the list above by the 2nd tuple components instead, I usually do
the more Perl-like

>>> def cmp_2nd_num( (dummy1, n1), (dummy2, n2) ) : return n1 - n2
...
>>> sort_by_2nd_num = make_sorter( cmp_2nd_num )
>>> sort_by_2nd_num( a )
[('b', 0), ('b', 2), ('aa', 3), ('a', 9)]
>>>

"make_sorter" is a function that takes a (Perl-like) comparison function
as argument, and returns a sorting function that sorts a list according
to the comparison function. I'll attach Python code for "make_sorter"
below; it's not intended to be industrial-strength (to the contrary, it
can be very wasteful of both time & space); I simply use this way for
convenience. Replace it with something smarter ...

> ...
> If there was no such a way, wouldn't it be worth to add this extension
> in some way to the builtin sort() method?

Well, if you're running Python then I'd guess you have the source code
for it: it is "worth it" to *you* to add this extension <grin>?

master-of-unfair-questions-ly y'rs - tim

Tim Peters Kendall Square Research Corp
tim@ksr.com, ksr!tim@uunet.uu.net

Following is one way to code up the `make_sorter' function used above:

class Sorter:
def init( self, cmp ):
self.Cmp = cmp
return self

def sort( self, list ):
# simple quicksort
if len(list) <= 1: return list

key = list[0]
less, same, greater = [], [], []
for thing in list:
outcome = self.Cmp( thing, key )
if outcome < 0: which = less
elif outcome > 0: which = greater
else: which = same
which.append( thing )

return self.sort(less) + same + self.sort(greater)

def make_sorter( cmp ):
# return a sorting function that sorts a list according to comparator
# function `cmp'
# cmp(a,b) should return < 0 if a < b
# = 0 if a = b
# > 0 if a > b
return Sorter().init( cmp ).sort

>>> END OF MSG