-1

I have a list of objects and for each object I calculated a corresponding function value, which I stored in another list. Now I want to sort both the lists according to this function value. I tried applying something I found at Sorting list based on values from another list? but that doesn't seem to work because '<' is not supported for an object (that's what the error says). In case it matters: several objects can have the same function value assigned to them.

For one of my attempts to solve this I tried using the code bellow but this gives a strange result. The list that is printed is [9, 8, 7, 0, 6, 5, 1, 2, 3, 4] and I do not see the logic behind this. Why doesn't this output [3,6,7,8,5,4,2,1,0]?

ranking = list(range(10))
test = [10,40,80,90,100,20,11,5,3,2]
print(sorted(ranking, key = lambda x: test[x]))
Uberfatty
  • 107
  • 1
  • 1
  • 4
  • I don´t get why is should be "[3,6,7,8,5,4,2,1,0]". "[9, 8, 7, 0, 6, 5, 1, 2, 3, 4]" is the correct ascending order. – Felix Kleine Bösing Dec 14 '20 at 14:54
  • test[9] = 2, so 9 under the key you defined is the minimum. The same logic applies for the rest of the elements – Dani Mesejo Dec 14 '20 at 14:54
  • 1
    Does your object implement these: https://docs.python.org/3/reference/datamodel.html#object.__lt__ – Tom Myddeltyn Dec 14 '20 at 14:57
  • 1
    Does this answer your question? [Sorting list based on values from another list?](https://stackoverflow.com/questions/6618515/sorting-list-based-on-values-from-another-list) – etch_45 Dec 14 '20 at 14:59
  • Why should the output be: [3,6,7,8,5,4,2,1,0]? – Dani Mesejo Dec 14 '20 at 15:00
  • What are those object that cannot be sorted by Python, and what would determine their order then? – Mr. T Dec 14 '20 at 15:01
  • Oh, now I see why it's [9, 8, 7, 0, 6, 5, 1, 2, 3, 4], I think I was confused because I was expecting the result to be the ranking of the elements in the list (so the 0 would be at the end because 2 is the smallest number in the the list "test"). – Uberfatty Dec 14 '20 at 15:10
  • @etch_45, no that didn't work for this problem since that only seems to work if both lists are sortable. In my case one lists contains objects from a self defined class and I got an error saying "'<' not supported between instances of 'candidate' and 'candidate'", (where 'candidate' is the name of the object). – Uberfatty Dec 14 '20 at 15:12

2 Answers2

0

You could make your object class directly sortable by implementing internal functions for the basic comparison operators. See here: https://docs.python.org/3/library/operator.html

For example:

class MyClass:

 def __lt__(a,b): 
     # your custom comparison logic, e.g.
     return a.specialAttribute < b.specialAttribute

 def __eq__(a,b): ...

This will allow you to use sorted() directly on a list of your object instances.

Alain T.
  • 40,517
  • 4
  • 31
  • 51
0

You don't want to sort the list; you want the rankings of its elements. Sorting and rankings are inverses of each other in the sense that [10, 40, 80, 90, 100, 20, 11, 5, 3, 2] has ranks [3, 6, 7, 8, 9, 5, 4, 2, 1, 0], and

sorted(enumerate([3, 6, 7, 8, 9, 5, 4, 2, 1, 0]), key=lambda pair: pair[1])
>>> [(9, 0), (8, 1), (7, 2), (0, 3), (6, 4), (5, 5), (1, 6), (2, 7), (3, 8), (4, 9)]

You can see the indices that would sort the list are the first elements of each pair.

Knowing this it's easy to go the other way as well.

ranking = range(10)
test = [10, 40, 80, 90, 100, 20, 11, 5, 3, 2]
sort_indices = sorted(ranking, key=lambda x: test[x])
rank_pairs = sorted(enumerate(x), key=lambda pair: pair[1])

>>> rank_pairs
[(3, 0), (6, 1), (7, 2), (8, 3), (9, 4), (5, 5), (4, 6), (2, 7), (1, 8), (0, 9)]

>>> [p[0] for p in rank_pairs]
 [3, 6, 7, 8, 9, 5, 4, 2, 1, 0]
BallpointBen
  • 9,406
  • 1
  • 32
  • 62