Reputation: 13
Given the following dict
:
class Object:
def __repr__(self): return "Object"
foo = {
1: [(10, Object()), (10, Object())],
2: [(11, Object()), (10, Object())]
}
sorted(foo.items(), key= lambda x : x[1][0], reverse=True)
Using sorted function, yields, as expected
[
(2, [(11, Object), (10, Object)]),
(1, [(10, Object), (10, Object)])
]
The problem arises when the first term is the same for all values in the dict
.
foo2 = {
1: [(10, Object()), (10, Object())],
2: [(10, Object()), (10, Object())]
}
Since __lt__()
isn't implemented in Object
, sorted()
throws a TypeError
exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Object' and 'Object'
In this case sorting would not be necessary but the algorithm I'm using needs to do it anyway.
What could I do to avoid this error?
Upvotes: 1
Views: 60
Reputation: 1121774
Just add more more index:
key=x[1][0][0]
Demo:
>>> sorted(foo2.items(), key=lambda x: x[1][0][0], reverse=True)
[(1, [(10, Object), (10, Object)]), (2, [(10, Object), (10, Object)])]
Tuples are compared lexicographically, first elements first, then second elements when the first are equal, etc. This is by design.
But if you don't want the whole tuple to be used in the sort, the solution is to not pass in the whole tuple. Pass in the first elements only and then ties are broken by taken the input order. For dictionaries in Python versions before 3.6, that means the order is not defined (see Why is the order in dictionaries and sets arbitrary?).
In my demo I used Python 3.7, and because the first element of the first tuple is 10 in both cases, the output is the same order as the definition order of the keys; 1 before 2.
Upvotes: 1