1

I need to sort this dict with two sequential criteria: "rank" descending, "fruit" ascending (in case of same ranking result).

The dict is structured in this way

'object':['fruit',rank]

For example I've:

myDict = {'item2': ['bananas', 3], 'item3': ['cocumbers', 11], 'item1': ['pinapples', 3], 'item4': ['pears', 3]}

My aim is to obtain this:

{'item3': ['cocumbers', 11], 'item2': ['bananas', 3],'item4': ['pears', 3], 'item1': ['pinapples', 3]}

with

sorted(myDict.items(), key=lambda (k, v): v[1], reverse=True)

I obtain only the correct sorting for rank but with no sorting order for the objects with the same ranking:

[('item3', ['cocumbers', 11]), ('item2', ['bananas', 3]), ('item1', ['pinapples', 3]), ('item4', ['pears', 3])]

How solve this in python 2.7?

Thank's

Vito
  • 1,201
  • 1
  • 10
  • 16
  • Dictionaries are not sequences, they cannot be sorted. See [this question](http://stackoverflow.com/questions/613183/python-sort-a-dictionary-by-value) for discussion. – unwind Jan 25 '13 at 15:42
  • @unwind: Incorrect. Dictionaries can be sorted, but the output can only be a list; I think you meant to say that they can't be sorted IN-PLACE – inspectorG4dget Jan 25 '13 at 15:44

2 Answers2

5

sorted(myDict.items(), key=lambda (k, v): (-v[1],v[0]))

should do the trick. Since rank is an integer, we can easily make it sort descending by making the key function just return the negative value rather than needing the reverse=True keywords to sorted. In the case of a tie, we fall back on the natural ordering of the strings.

This works because sequences in python sort lexicographically (tuples are a sequence type) -- Python compares elements from each sequence in order until one of the elements is non-equal which gives the ordering of your pair of sequences.

In the case where you can't easily replace reverse=True with a key function, you'll need to sort twice:

l1 = sorted(myDict.items(),key=lambda (k,v):v[0])
l1.sort(key=lambda (k,v):v[1],reverse=True)

This relies on the documented fact that a python sort must be stable. In other words, the relative order of elements that are equal is the same before and after sorting.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Very elegant! I was going to define a comparator function to use with `sorted`'s `cmp` param – inspectorG4dget Jan 25 '13 at 15:42
  • 1
    @inspectorG4dget -- I'd always advise against using `cmp`. It's less efficient (the key function is guaranteed to be called once per object, `cmp` could be called multiple times) and (more importantly) `cmp` is gone in python3.x – mgilson Jan 25 '13 at 15:44
0

You will need to use collections.OrderedDict to maintain order inside dicts.

Jakob Bowyer
  • 33,878
  • 8
  • 76
  • 91