How to sort a list of dictionaries by a list that might contain duplicate values?

In Python 3.9 sorting a list of most objects by a second list is easy, even if duplicates are present:

>>> sorted(zip([5, 5, 3, 2, 1], ['z', 'y', 'x', 'w', 'x']))
[(1, 'x'), (2, 'w'), (3, 'x'), (5, 'y'), (5, 'z')]

If this list to be sorted contains dictionaries, sorting generally goes fine:

>>> sorted(zip([3, 2, 1], [{'z':1}, {'y':2}, {'x':3}])) 
[(1, {'x': 3}), (2, {'y': 2}), (3, {'z': 1})]

However, when the list to be sorted by contains duplicates, the following error occurs:

>>>sorted(zip([5, 5, 3, 2, 1], [{'z':1}, {'y':2}, {'x':3}, {'w': 4}, {'u': 5}])) 
*** TypeError: '<' not supported between instances of 'dict' and 'dict'

The issue sees pretty crazy to me: How do the values of the list to be sorted even affect the list to be sorted by?

Alternative solution:
One, not so elegant solution would be:

>>> sort_list = [5, 5, 3, 2, 1]    
>>> dicts_list = [{'z':1}, {'y':2}, {'x':3}, {'w': 4}, {'u': 5}]
>>> [dicts_list[i] for _, i in sorted(zip(sort_list, range(len(sort_list))))]
 [{'u': 5}, {'w': 4}, {'x': 3}, {'z': 1}, {'y': 2}]

Related Questions on StackOverflow:
Many similar questions have been raised on StackOverflow, related to

This specific case, especially including duplicates has not been discussed yet.

>Solution :

The reason for this is the way tuple comparison works. Generally, if t1 and t2 are tuples, t1 < t2 if t1[0] < t2[0], however if t1[0] == t2[0], then it will compare t1[1] < t2[1] and so on. This means you can compare tuples even if they contain items that can’t be compared to each other, as long as the comparison can differentiate items that come before it.

The standard way to solve this is to provide a key function that ignores the dictionary:

sorted(zip([5, 5, 3, 2, 1], [{'z':1}, {'y':2}, {'x':3}, {'w': 4}, {'u': 5}]), key=lambda item: item[0])

Leave a Reply