22

I have to sort a list with multiple attributes. I can do that in ascending order for ALL attributes easily with

L.sort(key=operator.attrgetter(attribute))....

but the problem is, that I have to use mixed configurations for ascending/descending... I have to "imitate" a bit the SQL Order By where you can do something like name ASC, year DESC. Is there a way to do this easily in Python without having to implement a custom compare function?

1

3 Answers 3

35

If your attributes are numeric, you have this.

def mixed_order( a ):
    return ( a.attribute1, -a.attribute2 )

someList.sort( key=mixed_order )

If your attributes includes strings or other more complex objects, you have some choices.

The .sort() method is stable: you can do multiple passes. This is perhaps the simplest. It's also remarkably fast.

def key1( a ): return a.attribute1
def key2( a ): return a.attribute2

someList.sort( key=key2, reverse=True )
someList.sort( key=key1 )

If this is the only sort, you can define your own special-purpose comparison operators. Minimally, you need __eq__ and __lt__. The other four can be derived from these two by simple logic.

Sign up to request clarification or add additional context in comments.

4 Comments

thanks! callint sort() multiple times turned out to be the perfect solution for me!
Thanks for your answer! Just a bit of confusion regarding the first part; does returning a tuple perform a complex sort with higher index values taking lower precedence? I guess my question is more generally, how does cmp behave when handed two tuples? I looked around and can't find this documented.
eq can be derived from lt using simple logic. :)
it might be helpful to point out that using this approach you have to reverse your sorting order (as you have done).
8

A custom function will render your code more readable. If you have many sorting operations and you don't want to create those functions though, you can use lambda's:

L.sort(lambda x, y: cmp(x.name, y.name) or -cmp(x.year, y.year))

Comments

7

You can't, but writing the compare function is easy:

def my_cmp(a, b):
    return cmp(a.foo, b.foo) or cmp(b.bar, a.bar)
L.sort(my_cmp)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.