简体   繁体   中英

Sorted function in Python dictionary

I have a dictionary and I need to print the contents of dictionary first sorted by "value" if there is any value tie then I need to use "key" as a tie breaker so that the keys that have the identical values will be printed in alphabetic order.

final = OrderedDict(sorted(mydict.items(), key=lambda x: (x[1], x[0]), reverse=True))

for key, value in final.items():
    print(f'{key} : {value}')

but when the print command runs, it will display the output like the identical values have not been sorted as expected:

Action : 3
Romance : 2
Horror : 2
History : 2
Comedy : 2
Adventure : 1

The way it's supposed to print must be like:

Action : 3
Comedy : 2
History : 2
Horror : 2
Romance : 2
Adventure : 1

Any thoughts about how can I correct this issue?

{k: v for k, v in sorted(mydict.items(), key=lambda item: (-item[1], item[0]), reverse=False)}

reverse is applied after the sequence has been sorted according to key . You only want the comparison on x[1] to be reversed, not the final ordering. I would use functools.cmp_to_key to convert a comparison function to a key function.

from functools import cmp_to_key

# Redefined from Python 2 since Python 3 dropped it
def cmp(x, y):
    return -1 if x < y else 0 if x == y else 1

def genre_sort(x, y):
    # A bigger count is a smaller genre; otherwise, sort alphabetically
    # by name
    return cmp(y[1], x[1]) or cmp(x[0], y[0])
    
final = OrderedDict(sorted(mydict.items(), key=cmp_to_key(genre_sort)))

You want to reverse the sort for x[1] only so don't pass reverse=True here, instead use negative number trick:

final = OrderedDict(sorted(mydict.items(), key=lambda x: (-x[1], x[0])))

Why this answer when there are already three other ones?

In my opinion none of the other answers exposed the core of the problem described in the question, which is by the way already sufficiently answered here: https://stackoverflow.com/questions/20145842/python-sorting-by-multiple-criteria and here https://stackoverflow.com/questions/55866762/how-to-sort-a-list-of-strings-in-reverse-order-without-using-reverse-true-parame making it a candidate for becoming closed as a duplicate.

The feature of Python allowing to have a solution to the problem of sorting columns in different sorting orders is the fact that

Python's sort is stable allowing you to use consecutive sorts, using the rightmost criteria first, then the next, etc. ( Martijn Pieters ) .

That Python's sort algorithm is stable means that equal elements keep their relative order. So you can use a first sort on the second element (sorting in ascending order) and then sort again, on only the first element and in reverse order.

I have changed the dictionary listed in the question to having only string values what will not allow to use the 'trick' with negative number values in the key function to achieve the desired result to demonstrate what is said above.

The code below:

mydict = { 
    'Romance'   : '2', 
    'Adventure' : '1', 
    'Action'    : '3', 
    'Horror'    : '2', 
    'History'   : '2',
    'Comedy'    : '2',
}
mylist = list(mydict.items())
print(mylist)
print()
mylist = sorted(mylist)
print(mylist)
mslist = sorted(mylist, key=lambda x: (x[1]), reverse=True)
print(mslist)
from collections import OrderedDict
final = OrderedDict(mslist)
for key, value in final.items():
    print(f'  {key:10} : {value}')

creating following output:

[('Romance', '2'), ('Adventure', '1'), ('Action', '3'), ('Horror', '2'), ('History', '2'), ('Comedy', '2')]

[('Action', '3'), ('Adventure', '1'), ('Comedy', '2'), ('History', '2'), ('Horror', '2'), ('Romance', '2')]
[('Action', '3'), ('Comedy', '2'), ('History', '2'), ('Horror', '2'), ('Romance', '2'), ('Adventure', '1')]
  Action     : 3
  Comedy     : 2
  History    : 2
  Horror     : 2
  Romance    : 2
  Adventure  : 1

demonstrates what I am speaking about here.

From:

[('Action', '3'), ('Adventure', '1'), ('Comedy', '2'), ('History', '2'), ('Horror', '2'), ('Romance', '2')]
[('Action', '3'), ('Comedy', '2'), ('History', '2'), ('Horror', '2'), ('Romance', '2'), ('Adventure', '1')]

can be seen that the second sort moves only '('Adventure', '1')' keeping the order of all the other items.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM