3

First of all, apologies if this too naive (I am a beginner). I have the following type of list of lists, which I would like to first sort by the last member of the inner list in ascending order:

data =  [[1, .45, 0], [2, .49, 2], [3, .98, 0], [4, .82, 1], [5, .77, 1], [6, .98, 2] ]

I accomplish this by using : sorted(data,key=operator.itemgetter(2),reverse = True), which gives me:

[[1, .45, 0], [3, .98, 0],[4, .82, 1], [5, .77, 1], [2, .49, 2], [6, .98, 2]]

Now, I would like to sort within the sub-lists i.e. first sort the list with its last member as '0' using the middle member as the key, in descending order. Then sort the sub-list with '1' as its last member and so on. Note that number of elements in each sub-list are different and are not know. The final list should look like this:

[[3, .98, 0],[1, .45, 0], [4, .82, 1], [5, .77, 1], [6, .98, 2],[2, .49, 2] ]

The list is actually quite huge, therefore I am looking for an efficient implementation. Any guidance would be appreciated !

jdi
  • 90,542
  • 19
  • 167
  • 203
R.Bahl
  • 399
  • 6
  • 18
  • I think your second example is backwards...you sorted reverse right? – jdi Jun 27 '12 at 05:22
  • Apologies, I guess I made a mistake while typing. It should have been reverse = False. – R.Bahl Jun 27 '12 at 05:26
  • Just to delve a little more into this (as an answer has already been provided), what exactly are you trying to do before this step? There might be a better way of achieving your goal, rather than worrying about the inner sort component. For instance, if you're reading this data in from somewhere, it might make sense to sort as you load. It might also be possible to use generators rather than lists/dicts. It might help if you post another question asking "is there a better way to achieve X". Just a thought :) – Josh Smeaton Jun 27 '12 at 05:53
  • @JoshSmeaton: Thanks a lot for your suggestion ! I am generating these list, which form the values in a dictionary via a computation which can be thought of as, for avalues in someset(A) , for bvalues in someset(B) return avalues + bvalues i.e say return the sum of all the pairwise combinations in both the sets. The keys would then be the values in setA and the list would be its [corresponding sum will all the elements, paired with the corresponding element of setB]. I will also try to form a separate question, but any feedback is highly appreciated ! – R.Bahl Jun 27 '12 at 06:10
  • @R.Bahl you might want to look into the itertools package - it may have some functions that'd be useful to you. For instance, efficiently generating the pairwise combinations. Where you're getting the data from initially should also be a possible place for optimisation. The problem seems very abstract to me without more context. But yeah like I suggested, possibly another question might yield some nice solution. Good luck. – Josh Smeaton Jun 27 '12 at 06:22
  • @JoshSmeaton: Thanks for your suggestions Josh ! Let me go ahead and try to form another question on this. – R.Bahl Jun 27 '12 at 06:31

2 Answers2

4
>>> data =  [[1, .45, 0], [2, .49, 2], [3, .98, 0], [4, .82, 1], [5, .77, 1], [6, .98, 2] ]
>>> sorted(data, key=lambda x:(x[2], -x[1]))
[[3, 0.98, 0], [1, 0.45, 0], [4, 0.82, 1], [5, 0.77, 1], [6, 0.98, 2], [2, 0.49, 2]]

You can add extra terms to the lambda as required

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • Gah. You entered this 6 minutes ago, and it notified me just as I was submitting this (lag). Almost word for word – jdi Jun 27 '12 at 05:36
  • Thanks !! This works perfectly. Just to follow up on my earlier comment that the list is huge, for starters I am storing them in a dictionary as key: value pairs where , values are these lists and keys are some numbers. As the number of keys and the size of the list runs into thousands, it quickly becomes infeasible to rum them from ram. What should be the most optimized method of doing it ? I am kind of hesitant to store these huge dictionaries in memory while I sort the list associated with each key. – R.Bahl Jun 27 '12 at 05:38
  • @R.Bahl: Sort each one in place via: `aList.sort(...)` ? Then you aren't generating any overly duplicated memory. – jdi Jun 27 '12 at 05:40
  • @jdi: I agree with you. But, since the number of keys is large (>10,000) and each list corresponding to the value of the key may contain >20,000 small inner lists (which we just sorted), then is doing it in memory a good method of approaching it ? – R.Bahl Jun 27 '12 at 05:48
  • @R.Bahl, if you have enough RAM, doing the sort in memory is preferable. Sounds like you would need quite a lot of RAM to do this sort, but maybe it is possible with 16GB or so – John La Rooy Jun 27 '12 at 07:05
1

You can pass sorted multiple keys:

data =  [[1, .45, 0], [2, .49, 2], [3, .98, 0], [4, .82, 1], [5, .77, 1], [6, .98, 2] ]
sorted(data, key=lambda x: (x[2], -x[1]))

[[3, 0.98, 0],
 [1, 0.45, 0],
 [4, 0.82, 1],
 [5, 0.77, 1],
 [6, 0.98, 2],
 [2, 0.49, 2]]
jdi
  • 90,542
  • 19
  • 167
  • 203