elbaridne
elbaridne

Reputation: 13

sorted() automatically sorts by second element of tuple

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

Answers (1)

Martijn Pieters
Martijn Pieters

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

Related Questions