Question about sorted in Python 3.0rc1

Arnaud Delobelle arnodel at googlemail.com
Mon Sep 22 08:22:11 EDT 2008


On 22 Sep, 11:52, josh logan <dear.jay.lo... at gmail.com> wrote:
> On Sep 22, 3:41 am, Arnaud Delobelle <arno... at googlemail.com> wrote:
>
>
>
> > On 22 Sep, 04:05, josh logan <dear.jay.lo... at gmail.com> wrote:
>
> > > Hello,
>
> > > I have 2 questions. Say I have this class:
>
> > > class Player(object):
> > >     def __init__(self, fname, lname, score):
> > >         self.score = score
> > >         self.fname = fname
> > >         self.lname = lname
> > >     def __cmp__(self, other):
> > >         return (-cmp(self.score, other.score) or
> > >                 cmp(self.lname, other.lname) or
> > >                 cmp(self.fname, other.fname))
> > >     def __repr__(self):
> > >         return 'Player(fname={0.fname}, lname={0.lname},
> > > score={0.score})'.format(self)
> > >     def __eq__(self, others):
> > >         if isinstance(other, Player):
> > >             return (self.score == other.score and
> > >                     self.lname == other.lname and
> > >                     self.fname == other.fname)
> > >         return False
> > >     def __ne__(self, others):
> > >         return not self.__eq__(others)
>
> > > fnames = ['Julie', 'Ben', 'Jason', 'David']
> > > lnames = ['Parks', 'Smith']
> > > scores = [100, 95, 95, 130, 58, 74]
>
> > > import itertools as it
>
> > > score_iter = it.cycle(scores)
>
> > > P = [Player(fn, ln, next(score_iter)) for fn in fnames for ln in
> > > lnames]
>
> > > cmp(P[0], P[1]) # returns -1
>
> > > sorted(P) # throws TypeError: unorderable types Player() < Player()
>
> > > The sorted function works when I define __lt__.
> > > I must be misreading the documentation, because I read for the
> > > documentation __cmp__ that it is called if none of the other rich
> > > comparison functions are defined.
> > > Is this a bug in Python 3.0rc1, or am I missing something?
>
> > > Secondly, say that we suddenly need another sorting order, where we
> > > want to sort by decreasing score and then by DECREASING last name
> > > (instead of increasing last name, defined above). Now that the
> > > comparison function argument is taken away from the sorted builtin,
> > > how do we accomplish this with the "key" parameter?
>
> > > Thank you
>
> > I don't know about __cmp__ but for the second part of the question you
> > can probably do:
>
> >     sorted(P, key=lambda p: (p.score, p.lname), reverse=True)
>
> > HTH
>
> > --
> > Arnaud
>
> Thank you for the prompt reply. I didn't think my second question
> completely through.
>
> A better example would be sorting by increasing last name and
> decreasing first name. This would be easy with the sort function
> comparator, but I can't see how to do the same with the key argument.
> Is the only solution to decorate the Player objects in another class
> that has the appropriate __cmp__ function (or whatever is needed) and
> then retrieve the Player objects back?

You can use the stability of the sorting algorithm as Peter pointed
out.  If decorating, you don't need to decorate the Player objects,
but you can decorate the keys instead: e.g

class RevStr(str):
    def __lt__(self, other): return str.__lt__(other, self)
    def __ge__(self, other): retrn str.__gt__(other, self)

then you can write:

sorted(P, key=lambda p:(p.lname, RevStr(p.fname)))

--
Arnaud



More information about the Python-list mailing list