I have a list of lists:
[[12, 'tall', 'blue', 1],
[2, 'short', 'red', 9],
[4, 'tall', 'blue', 13]]
If I wanted to sort by one element, say the tall/short element, I could do it via s = sorted(s, key = itemgetter(1))
.
If I wanted to sort by both tall/short and colour, I could do the sort twice, once for each element, but is there a quicker way?
Here's one way: You basically re-write your sort function to take a list of sort functions, each sort function compares the attributes you want to test, on each sort test, you look and see if the cmp function returns a non-zero return if so break and send the return value. You call it by calling a Lambda of a function of a list of Lambdas.
Its advantage is that it does single pass through the data not a sort of a previous sort as other methods do. Another thing is that it sorts in place, whereas sorted seems to make a copy.
I used it to write a rank function, that ranks a list of classes where each object is in a group and has a score function, but you can add any list of attributes. Note the un-lambda-like, though hackish use of a lambda to call a setter. The rank part won't work for an array of lists, but the sort will.
Here's a way to rank a list of objects
A key can be a function that returns a tuple:
Or you can achieve the same using
itemgetter
(which is faster and avoids a Python function call):And notice that here you can use
sort
instead of usingsorted
and then reassigning:I'm not sure if this is the most pythonic method ... I had a list of tuples that needed sorting 1st by descending integer values and 2nd alphabetically. This required reversing the integer sort but not the alphabetical sort. Here was my solution: (on the fly in an exam btw, I was not even aware you could 'nest' sorted functions)
It appears you could use a
list
instead of atuple
. This becomes more important I think when you are grabbing attributes instead of 'magic indexes' of a list/tuple.In my case I wanted to sort by multiple attributes of a class, where the incoming keys were strings. I needed different sorting in different places, and I wanted a common default sort for the parent class that clients were interacting with; only having to override the 'sorting keys' when I really 'needed to', but also in a way that I could store them as lists that the class could share
So first I defined a helper method
then to use it
This will use the generated lambda function sort the list by
object.attrA
and thenobject.attrB
assumingobject
has a getter corresponding to the string names provided. And the second case would sort byobject.attrC
thenobject.attrA
.This also allows you to potentially expose outward sorting choices to be shard alike by a consumer, a unit test, or for them to perhaps tell you how they want sorting done for some operation in your api by only have to give you a list and not coupling them to your back end implementation.