2

I'm using Python 3.8. I am trying to sort players by points (in descending order) and then, only if they have the same number of points, by rank.

I've already read Sorting HOW TO, Python sorting by multiple criteria and Sorting by multiple conditions in python.

Here's my code:

from operator import itemgetter

players_results = [
    ("Pierre", 1.0, 1),
    ("Matthieu", 1.0, 2),
    ("Joseph", 0.5, 3),
    ("Marie", 0.0, 4),
    ("Michel", 0.5, 5),
    ("Raphael", 0.0, 6),
]

sorted_by_points = sorted(players_results, key=itemgetter(1), reverse=True)
points_descending_rank_ascending = sorted(sorted_by_points, key=itemgetter(2))
print(points_descending_rank_ascending)

# [('Pierre', 1.0, 1), ('Matthieu', 1.0, 2), ('Joseph', 0.5, 3), ('Marie', 0.0, 4), ('Michel', 0.5, 5), ('Raphael', 0.0, 6)]

In each tuple, the number of points are of float type while the rank is of integer type. My problem is that Michel should be before Marie, but that's not the case. Can someone explain what I have to implement differently?

6
  • Answers on both of the SO questions you link suggest sorting on a tuple key, which you're not doing. You're sorting twice, not using multiple criteria simultaneously. Commented Dec 7, 2021 at 17:02
  • Does this answer your question? Python sorting by multiple criteria Commented Dec 7, 2021 at 17:04
  • " if all the other criteria are numeric, then negate their values for the sort key and add reverse=True. Otherwise, use consecutive sorts, using the rightmost criteria first, then the next, etc" Martijn Peters. What should I do if the values aren't numeric and I want to combine an ascending and a descending criteria ? Commented Dec 7, 2021 at 17:11
  • "What should I do if the values aren't numeric..." - why do you ask? The values you want to sort on are numeric. Commented Dec 7, 2021 at 17:12
  • @jonrsharpe you're right, but I may need it later in my project Commented Dec 7, 2021 at 17:15

3 Answers 3

2

One solution could be:

sorted(players_results, key=lambda x:(-x[1],x[2]))

OUTPUT

[('Pierre', 1.0, 1), ('Matthieu', 1.0, 2), ('Joseph', 0.5, 3), ('Michel', 0.5, 5), ('Marie', 0.0, 4), ('Raphael', 0.0, 6)]
Sign up to request clarification or add additional context in comments.

Comments

0

I suggest using 3rd party libraries, such as pandas:

import pandas as pd

players_results = [
    ("Pierre", 1.0, 1),
    ("Matthieu", 1.0, 2),
    ("Joseph", 0.5, 3),
    ("Marie", 0.0, 4),
    ("Michel", 0.5, 5),
    ("Raphael", 0.0, 6),
]
df = pd.DataFrame(players_results)
df.columns = ["name", "points", "rank"]
df.sort_values(["points", "rank", "name"], ascending=[False, True, True])

result

Comments

-1

Attemping to respect your script, something like this works:

if __name__ == '__main__':

    players_results = [
        ("Pierre", 1.0, 1),
        ("Matthieu", 1.0, 2),
        ("Joseph", 0.5, 3),
        ("Marie", 0.0, 4),
        ("Michel", 0.5, 5),
        ("Raphael", 0.0, 6),
    ]


    # In one line:
    points_descending_rank_ascending = sorted(players_results, key=lambda t: (-t[1], t[2]))
    print(points_descending_rank_ascending)

4 Comments

I just wrote the script using old script. I add the simplest line.
My point is that you didn't add the simplest line, and you've left one in that's totally redundant (both versions work in one line, neither requires the pre-sorting). In addition it's more helpful to write answers that explain what you've changed, why that works and why the original didn't.
I have added the simplest line, now.
Sorry, I re-edit all to be clear.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.