Alright so I created a leaderboard and I made it to display the players with the most wins. For some reason when there is multiple people with the same amount of wins it just displays one persons name over and over again.
Here is the main.py
@client.command()
@commands.cooldown(1,5, BucketType.user)
async def leaderboard(ctx, x = 1):
users = await get_win_data()
leader_board = {}
total = []
for user in users:
name = int(user)
total_amount = users[user]["Wins"]
leader_board[total_amount] = name
total.append(total_amount)
total = sorted(total, reverse=True)
demb = discord.Embed(title = f"Top winners!", descripition = "These are the people with the most amount of wins.", color=discord.Color.red())
index = 1
for wins in total:
id_ = leader_board[wins]
member = client.get_user(id_)
name = member.name
demb.add_field(name = f"{index}. {name}", value=f"Won **{wins}** times", inline=False)
if index == x:
break
else:
index = 1
await ctx.send(embed = demb)
Here is the json
{
"427924596164132864": {
"Wins": 1
},
"441638109587832842": {
"Wins": 1
},
"479527342860140544": {
"Wins": 1
}
}
I was wondering if there was any way to make it display all 3 players even though they're all at the same win count.
CodePudding user response:
A dictionary can directly access (key, value)
pairs using items()
and then sort based on value as described at How do I sort a dictionary by value?
The final simplified code will be:
@client.command()
@commands.cooldown(1,5, BucketType.user)
async def leaderboard(ctx, x = 1):
users = await get_win_data()
iterator = sorted(users.items(), key=lambda item: item[1]["Wins"], reverse=True)
demb = discord.Embed(title = f"Top winners!", descripition = "These are the people with the most amount of wins.", color=discord.Color.red())
count = 1
for id_, data in iterator:
member = client.get_user(id_)
if member is not None:
demb.add_field(name = f"{count}. {member.name}", value=f"Won **{data['Wins']}** times", inline=False)
if count == x:
break
else:
count = 1
else:
# Handle missing users based on your application
print(f"user ID {id_} is missing.")
await ctx.send(embed = demb)
Just like in your code, this takes the first x
values in descending order. If you want, you can modify the lambda passed to sorted()
to enforce additional ordering for when wins are the same. By default they'll just maintain whatever order is already in users
.
Your original code could have been made to work (for example, by mapping each score to a list
rather than an int
name directly), but those intermediate structures themselves are not necessary. The main cause of your bug was that each score only maps to one name, so the last name with that score is the only one it knows. Meanwhile total
had that score stored multiple times, and each time it would print the same (last) name.
Update based on chat: Apart from some typos, the main issue was that the get_user
discord API returns None
if it can't find the user. OP will be looking into that problem, but this code solves the sorting issue if we just add a simple if member is not None
check.