0

I am working on a discord.py bot and when I am trying to sort the balance of each user for a "top balance" command, it stops sorting correctly if keys have 3 digit numbers.

# bot and discord are defined above here, btw
@bot.command(name='top')
async def top(context):
    scores.read("brewscores.ini")
    tops = scores['scores']
    print('hi\n', tops)
    print('sotred')
    from collections import Counter #todo : move this somewhere else
    c = Counter(tops)
    a = c.most_common(5) #//https://stackoverflow.com/a/40496562/9654083
    string = """"""
    await context.send("Loading balancers...")
    for item in a:
        print(item)
        g, s = item
        string += (f"{g}: {s}\n")
    em = discord.Embed(title="Top 5 Balancers", description=f'The top 5 contestants are!:{string}')
    await context.send(embed=em)

The scores:

[scores]
placeholder = 0
(username censored for privacy) = 35
(username censored for privacy) = 49
No other balancers! = 0
You can stop reading now... = 0
rats#3234 = 100

Output both me and the owner get in Discord when running the command:

(censored for privacy): 49
(censored for privacy): 35
rats#3234: 100
placeholder: 0
you can stop reading now...: 0

The one we expect:

rats#3234: 100
(censored for privacy): 49
(censored for privacy): 35
placeholder: 0
you can stop reading now...: 0

Notice how "rats#3234" was misplaced. We did not see this behaviour in 2- or 1-digit numbers like 99 or 3. Why does this occur?

2 Answers2

1

There is no need for Counter:

scores.read("brewscores.ini")
print(scores)
tops = scores["scores"]
sortedtopkeys = sorted(tops, key=lambda k: int(tops[k]), reverse=True)
print(sortedtopkeys)

This way you sort the dict on the values, as shown in the answer you have in the comment, but interpreting the value as an int.

Cheers!

Pietro
  • 915
  • 2
  • 8
  • 14
0

update

see https://stackoverflow.com/a/66821488/9654083 for a better answer if you don't care about the details of why this error occurs. imo this answer best supplements that answer, not replace.

So it turns out that when it's a string, collections.Counter.most_common looks at the first digit first to figure out which is greater, then the second, then the third. Not it all together.

So that means, this:

[scores]
placeholder = 0
(censored) = 35
(censored) = 49
rats#3234 = 9

will put rats first since it sees it as

[scores]
placeholder = 0
(censored) = 3
(censored) = 4
rats#3234 = 9

If there are two ones with the same first digit, it will continue by comparing the first and second digit:

[scores]
placeholder = 0
(censored for privacy) = 35
(censored) = 49

instead of just the first digit, and so on.

This means that contrary to what we thought, it is not just because it's 3 digits. It's because it has the largest first digit.

The other developer found this out because 9 being the value of rats would output

rats#3234: 9
(censored): 49
(censored): 35
placeholder: 0

This means that we should have to convert to int before sorting.

Give me one second while I test.