sorting ascending/descending with operator.attrgetter

C

Chris Curvey

I must be having a brain cramp. Given a list of objects, how can I
sort the list on one attribute in descending order, then sort within
each group in ascending order on another attribute.

For example:

class Foo:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c


I can do "allmyfoos.sort(operator.attrgetter('a','b'))" to sort
ascending on both attributes, but how could i sort by "a, descending,
then b, ascending)?"
 
T

Tim Golden

I must be having a brain cramp. Given a list of objects, how can I
sort the list on one attribute in descending order, then sort within
each group in ascending order on another attribute.

For example:

class Foo:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c

I think this is the kind of thing you're after...

http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/

.... at least the link to the Wiki should help:

http://wiki.python.org/moin/HowTo/Sorting

TJG
 
P

Peter Otten

Chris said:
I must be having a brain cramp. Given a list of objects, how can I
sort the list on one attribute in descending order, then sort within
each group in ascending order on another attribute.

For example:

class Foo:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c


I can do "allmyfoos.sort(operator.attrgetter('a','b'))" to sort
ascending on both attributes, but how could i sort by "a, descending,
then b, ascending)?"

In the general case you have to sort twice:
from collections import namedtuple
Foo = namedtuple("Foo", "a b")
items = [Foo(x, y) for x in range(3) for y in range(3)]
def show(items):
.... for item in items: print item
....Foo(a=0, b=0)
Foo(a=0, b=1)
Foo(a=0, b=2)
Foo(a=1, b=0)
Foo(a=1, b=1)
Foo(a=1, b=2)
Foo(a=2, b=0)
Foo(a=2, b=1)
Foo(a=2, b=2)Foo(a=2, b=0)
Foo(a=2, b=1)
Foo(a=2, b=2)
Foo(a=1, b=0)
Foo(a=1, b=1)
Foo(a=1, b=2)
Foo(a=0, b=0)
Foo(a=0, b=1)
Foo(a=0, b=2)

This is guaranteed to work because list.sort() is "stable", i. e. it doesn't
alter the order of items with equal keys.

Peter
 
P

Patrick Maupin

I must be having a brain cramp.  Given a list of objects, how can I
sort the list on one attribute in descending order, then sort within
each group in ascending order on another attribute.

For example:

class Foo:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

I can do "allmyfoos.sort(operator.attrgetter('a','b'))" to sort
ascending on both attributes, but how could i sort by "a, descending,
then b, ascending)?"

You can provide a cmp function to the string sort method, e.g. cmp =
lambda x,y: -cmp(x.a, y.a) or cmp(x.b, y.b)

You can also possibly gain some efficiency by using key instead of
cmp.
For example, if one of the objects is numeric, you can call sort()
with something like key = lambda x:(-x.a, x.b)

Or if b is numeric but a is a string, you could use lambda x:(x.a, -
x.b) and then use list.reverse() afterward.

HTH,
Pat
 
R

Raymond Hettinger

I must be having a brain cramp.  Given a list of objects, how can I
sort the list on one attribute in descending order, then sort within
each group in ascending order on another attribute.

For example:

class Foo:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

I can do "allmyfoos.sort(operator.attrgetter('a','b'))" to sort
ascending on both attributes, but how could i sort by "a, descending,
then b, ascending)?"

Rely on sort stability and do two passes:

allmyfoos.sort(operator.attrgetter('b'))
allmyfoos.sort(operator.attrgetter('a'), reverse=True)


Raymond
 
S

Steven D'Aprano

You can provide a cmp function to the string sort method, e.g. cmp =
lambda x,y: -cmp(x.a, y.a) or cmp(x.b, y.b)

String sort method?
Traceback (most recent call last):
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'sort'

Did you mean list sort method?


You can also possibly gain some efficiency by using key instead of cmp.

That is an impressive understatement. key is called once for every item,
cmp is called once for every comparison. cmp has been dropped from Python
3.x because its performance is poor.
 
P

Patrick Maupin

Did you mean list sort method?

Why, yes. Yes, I did. Yes, I'm an old forgetful man who sometimes
misspeaks or mistypes, and you're the smartest, sharpest guy in the
world. Most helpful, too. It's much more useful to show how I'm wrong
than to provide useful info to the OP. Teaches people not to quickly
post on CLP to try to help out people with immediate problems. No, it
would have been much more useful for me to self-edit my post for a
couple of days before posting.

Doesn't matter though. The OP was sorting lists, not strings, so he
knew what I meant.
That is an impressive understatement. key is called once for every item,
cmp is called once for every comparison. cmp has been dropped from Python
3.x because its performance is poor.

Yes, well, I did have the "Use a key" statement before "use
cmp" (before I did the tiny bit of editing I did before posting) and
then it occurred to me that he might be sorting with strings, so I
thought I would give him something that worked, and then something
that might work better under some circumstances.

And, BTW, if he is only occasionally
sorting a few short strings^H^H^H^H^H^H^Hlists,
he'll never notice a performance difference. But at least you can
take comfort that he now knows how superior your intellect is to mine.

Of course, he might accidentally underestimate Peter and Raymond's
intellect. They published dual sort solutions that are, for most
cases, probably better than the single sort solution I published, but
neglected to call attention to just how bad my suggestion was.
 
S

Steven D'Aprano

Doesn't matter though. The OP was sorting lists, not strings, so he
knew what I meant.

I have found that when people ask basic questions about fundamental
Python operations like sorting, it is risky to assume that they will know
what I meant if I say something different.

Since I've been on both the giving and receiving end of carelessly
inaccurate answers, I know how frustrating it is to spend significant
time trying to work out what I was doing wrong, only to be told much
later "Oh, I meant you should do Y, not X. I thought you would understand
what I meant."
 
S

Steve Holden

Steven said:
I have found that when people ask basic questions about fundamental
Python operations like sorting, it is risky to assume that they will know
what I meant if I say something different.

Since I've been on both the giving and receiving end of carelessly
inaccurate answers, I know how frustrating it is to spend significant
time trying to work out what I was doing wrong, only to be told much
later "Oh, I meant you should do Y, not X. I thought you would understand
what I meant."
But you surely will admit that you could be held to, well rather than
"be pedantic" perhaps we should say "tend towards the literal"?

I'm the same myself, and I know from personal experience that while I am
(simply?) seeking accuracy and truth it sometimes bugs the hell out of
people ...

It's a geek thing.

regards
Steve
 
S

Steven D'Aprano

But you surely will admit that you could be held to, well rather than
"be pedantic" perhaps we should say "tend towards the literal"?

I wouldn't so much say "literal" as "precise".

*wink*

I'm the same myself, and I know from personal experience that while I am
(simply?) seeking accuracy and truth it sometimes bugs the hell out of
people ...

If you think I'm pedantic, you should see some of the guys I work with.
I'm frequently on the receiving end of technical corrections. Yes, it's
annoying to be in full flow explaining something, only to have somebody
point out that you've made a silly mistake, or totally got something
wrong, or what you've been calling a NAT device (including to the client)
for a week is actually a NAS device *cough*. Annoying or not, if somebody
had corrected me earlier, I wouldn't have looked quite so ignorant for
quite so long, so all things considered I'd prefer to have my mistakes
pointed out so I can stop making them.

It's a geek thing.

Heavens, geeks on a programming forum! Who could possibly have expected
such a thing?
 
S

Steven D'Aprano

I'm the same myself, and I know from personal experience that while I am
(simply?) seeking accuracy and truth it sometimes bugs the hell out of
people ...

By the way, why are we acting as if seeking accuracy and truth is a bad
thing?

Personally, if I were interviewing job applicants, one of the things I'd
like to know is how well they react to criticism. This especially applies
to technical and programming roles. I've managed thin-skinned prima
donnas who spit the dummy if someone dares point out they made a mistake,
and so long as I'm involved in the hiring process I won't be doing so
again. Give me a pedantic, technically precise, obnoxiously *correct*
coder over a sloppy one any time.
 
P

Patrick Maupin

I wouldn't so much say "literal" as "precise".

Being precise in your own words is an admirable trait. Asking others
to be more precise can be done politely when necessary, but in this
case it obviously wasn't necessary, since even you, who deliberately
misinterpret everything I write, knew that I was really talking about
lists.
If you think I'm pedantic, you should see some of the guys I work with.

I can well imagine that everybody who has to work with you thoroughly
enjoys proving you wrong as often as possible. I would expect they
are probably much gentler to each other in your absence. OTOH, if I
am wrong, I certainly wouldn't last long there -- I've left less
poisonous workplaces for less cause.
I'm frequently on the receiving end of technical corrections. Yes, it's
annoying to be in full flow explaining something, only to have somebody
point out that you've made a silly mistake, or totally got something
wrong, or what you've been calling a NAT device (including to the client)
for a week is actually a NAS device *cough*. Annoying or not, if somebody
had corrected me earlier, I wouldn't have looked quite so ignorant for
quite so long, so all things considered I'd prefer to have my mistakes
pointed out so I can stop making them.

There is a (not very subtle) difference between saying "Oh, you meant
a list, not a string" (especially when the context was a discussion of
list processing), and printing a traceback for something that nobody
was discussing, based on a single word slip.
Heavens, geeks on a programming forum! Who could possibly have expected
such a thing?

Mr. Holden was being unfailingly polite, in trying to point out that
many individuals who have a reasonably high intellect, yet zero social
skills, will gravitate toward technical fields. When he was asking
you to admit that you "tend toward the literal" (which naturally you
refused to do) I think he may have been trying to gently explain that
introspection is not just for Python anymore.

Regards,
Pat
 
P

Patrick Maupin

By the way, why are we acting as if seeking accuracy and truth is a bad
thing?

I don't think anybody is acting like that is a bad thing. It's all
how you choose to interpret things.
Personally, if I were interviewing job applicants, one of the things I'd
like to know is how well they react to criticism. This especially applies
to technical and programming roles. I've managed thin-skinned prima
donnas who spit the dummy if someone dares point out they made a mistake,
and so long as I'm involved in the hiring process I won't be doing so
again. Give me a pedantic, technically precise, obnoxiously *correct*
coder over a sloppy one any time.

It's interesting you should mention this. In my experience, the best
coders accept criticism well, and aren't usually very critical
themselves, except when asked to be. Also, they are usually capable
of reading between the lines and discerning and appropriately reacting
to subtle behavioral criticism, not just technical criticism. But
then, I have the best boss and group of co-workers in the world, so
what would I know?

Regards,
Pat
 
S

Steve Holden

Patrick said:
Being precise in your own words is an admirable trait. Asking others
to be more precise can be done politely when necessary, but in this
case it obviously wasn't necessary, since even you, who deliberately
misinterpret everything I write, knew that I was really talking about
lists.


I can well imagine that everybody who has to work with you thoroughly
enjoys proving you wrong as often as possible.

I am glad I wasn't drinking when I read this. Liquid in one's nose is so
uncomfortable.
I would expect they are probably much gentler to each other in your
absence. OTOH, if I am wrong, I certainly wouldn't last long there
-- I've left less poisonous workplaces for less cause.


There is a (not very subtle) difference between saying "Oh, you meant
a list, not a string" (especially when the context was a discussion
of list processing), and printing a traceback for something that
nobody was discussing, based on a single word slip.


Mr. Holden was being unfailingly polite, in trying to point out that
many individuals who have a reasonably high intellect, yet zero
social skills, will gravitate toward technical fields. When he was
asking you to admit that you "tend toward the literal" (which
naturally you refused to do) I think he may have been trying to
gently explain that introspection is not just for Python anymore.
Nicely put (though I have to question the accuracy of "unfailingly
polite" if it was intended as a generic description of my behavior.

I guess we have to value the good that's in Steven (few would deny that
he *is* technically very competent) and try and ignore his more annoying
side.

I have toyed many times with the idea of giving a presentation at PyCon
called something like "Humanity 101". It would include such advice as
"When I say 'use soap' I am not talking about the Simple Object Access
Protocol" and "Being wrong is usually survivable; offending a homicidal
maniac often isn't".

Perhaps I should just add it to the Holden Web course schedule?

regards
Steve
 
S

Steve Holden

Steven said:
By the way, why are we acting as if seeking accuracy and truth is a bad
thing?
We aren't. Or, at least, I'm not trying to convey that. But you have to
remember you aren't conversing with robots here. People have emotions,
and they will affect the way they react to your utterances whether you
like or not, and whether you think it's reasonable or not.
Personally, if I were interviewing job applicants, one of the things I'd
like to know is how well they react to criticism. This especially applies
to technical and programming roles. I've managed thin-skinned prima
donnas who spit the dummy if someone dares point out they made a mistake,
and so long as I'm involved in the hiring process I won't be doing so
again. Give me a pedantic, technically precise, obnoxiously *correct*
coder over a sloppy one any time.
As an employee, possibly (though the expense of stopping his colleagues
from killing him may make the cost prohibitive). As a friend, one might
be prepared to be forgiving.

As a Usenet correspondent I find that too much pedantry becomes tiresome
after a while, and can detract from the pleasures of the correspondence.
It should hardly be necessary to point out that you *aren't*
interviewing job applicants on c.l.py (or at least not overtly).

regards
Steve
 
S

Steven D'Aprano

There is a (not very subtle) difference between saying "Oh, you meant a
list, not a string" (especially when the context was a discussion of
list processing), and printing a traceback for something that nobody was
discussing, based on a single word slip.

I wondered about that.

I almost asked whether or not you would have reacted with less anger if I
hadn't included the tracebacks, but decided against it. I thought that,
given how you dropped a nuke on me for what was a very trivial social
faux pas, you would probably interpret a question about the tracebacks as
me being condescending and go on the attack yet again.

So far you've dropped a ton of sarcasm on me for being "the smartest,
sharpest guy in the world", accused me of "deliberately
misinterpret[ing] everything [you] write", and declared that my work-
mates (who you don't know) take great pleasure in putting me down. Such
repeated attacks, over something as trivial as me pointing out you
mistook list.sort for str.sort puts your comment:

"I've left less poisonous workplaces for less cause."

into a completely different perspective. How little a slight does it take
for you to decide a workplace is poisonous?

So, Patrick, here's how it goes:

I won't apologize for pointing out your error, no matter how trivial,
because I thought, and still do, that it muddied the waters and risked
adding confusion rather than clarity to somebody asking a very basic
question. And for all I knew, you may have been genuinely confused
yourself, and not just making a silly typo.

I will say that I regret including the tracebacks, not because there is
anything wrong with doing so, but because they apparently caused you
distress and I had no intention to do so. I am sorry that you took
offense, it was not intended.

At the risk of offending you further, I will suggest that I'm not the
only one who needs to apply some introspection here. If your skin is so
thin that you react so explosively to such a minor slight, how are you
going to react to some of the more vigorous disagreements?
 
P

Patrick Maupin

At the risk of offending you further, I will suggest that I'm not the
only one who needs to apply some introspection here. If your skin is so
thin that you react so explosively to such a minor slight, how are you
going to react to some of the more vigorous disagreements?

I think, if you go back and read other threads, you will find that a)
I react fine to even very vigorous technical disagreements, and b) my
reaction to you in particular (which, yes, introspection does show
that I need to not react right away) is because of an induced
sensitivity. Perhaps I'll see my allergist.

Regards,
Pat
 
P

Patrick Maupin

I am glad I wasn't drinking when I read this. Liquid in one's nose is so
uncomfortable.

Well, in that case, I'm glad you enjoyed it. It's hard to know when
to put a disclaimer on these things. Others might not find the same
sorts of things funny, and the very act of putting a disclaimer often
promises more than it delivers, so I think it's pretty much just
"caveat reader."
I guess we have to value the good that's in Steven (few would deny that
he *is* technically very competent) and try and ignore his more annoying
side.

Well, I suppose there are two coping strategies. Ignoring him (yes, I
need to do that more), and also, reading more carefully before
posting. The latter is always a good thing, but on the other hand it
takes more mental effort. Yes, it's better for posterity, but someone
reading the thread later and seeing what is written in context will
probably figure out what is meant, even if there are a few mistakes.
The extra effort shifts the balance from "will this help the OP?" to
"if this email were read completely devoid of external context, how
many ways are there to mis-interpret it, and how much time am I
willing to spend reducing that number, when it's impossible to get it
to zero, anyway?"
I have toyed many times with the idea of giving a presentation at PyCon
called something like "Humanity 101". It would include such advice as
"When I say 'use soap' I am not talking about the Simple Object Access
Protocol" and "Being wrong is usually survivable; offending a homicidal
maniac often isn't".

Perhaps I should just add it to the Holden Web course schedule?

Well, I haven't killed anybody yet; OTOH a few events from my
childhood taught me that there are really only two kinds of people:
those who could kill under the right circumstances, and those who
haven't figured it out yet. So, yes, that might be a good idea ;-)

Regards,
Pat
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top