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?

TheTechRobo the Nerd
  • 1,249
  • 15
  • 28
  • Can you provide a snippet with the content of `tops` that work as you expect and one that does not? How are you splitting the score from the name? What are you counting? – Pietro Mar 26 '21 at 16:48
  • I edited the question, does that now answer your quesiton? – TheTechRobo the Nerd Mar 26 '21 at 16:51
  • Not exactly: do you want to sort the rows of the file based on the score? What is inside `scores` and `tops` after you read the `ini` file? Even more important to reproduce your code, what is `scores`? – Pietro Mar 26 '21 at 16:55
  • `scores` is the ini file read. `tops` is the contents of the `scores` part of `scores`. I actually have a solution, I'll provide an answer just now. – TheTechRobo the Nerd Mar 26 '21 at 16:58
  • Ok cool, btw I meant `scores.read("brewscores.ini")`: where do you define `scores`? What python object is that? – Pietro Mar 26 '21 at 17:00
  • That's `scores = configparser.ConfigParser()` I believe. – TheTechRobo the Nerd Mar 26 '21 at 17:00
  • Ok that helped: I think that the problem is that when you read the `.ini` file, the values are interpreted as `str`. That is why the sort does not work, `100` comes before `99` if you order lexicographically and not as numbers. – Pietro Mar 26 '21 at 17:07
  • Ohhh... so our answer is only correct when it's strings! Thanks, I'll update the answer. :D – TheTechRobo the Nerd Mar 26 '21 at 17:07

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
  • 1,090
  • 2
  • 9
  • 15
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.

TheTechRobo the Nerd
  • 1,249
  • 15
  • 28