0

I was trying to make a leaderboard command for my level system on discord.py with JSON but for some weird reason, it won't work. Only the top 3 highest level players are shown instead of the top 5 and when I try to give a ton of exp to another player to change the 1st position the last 1st place player does not go to the 2nd place but is nowhere to be found. image of the output

Here is the output image, on the top is the output from when I hadn't changed Void's exp, and on the bottom is when I changed Void's exp.

    # leaderboard command
    @commands.command(name='leaderboard', aliases=['lb', 'top', 'levels'])
    async def leaderboard(self, ctx, arg:str=None):
        try:
            with open(levelsJSON, 'r') as levels_file:
                    levels = json.load(levels_file)

           ## Top 5 places VARIABLES
            first_name = 'N/A'
            first_level = 0
            first_exp = 0
            second_name = 'N/A'
            second_level = 0
            second_exp = 0
            third_name = 'N/A'
            third_level = 0
            third_exp = 0
            fourth_name = 'N/A'
            fourth_level = 0
            fourth_exp = 0
            fifth_name = 'N/A'
            fifth_level = 0
            fifth_exp = 0

           ## Variables END

            # loops through the file
            for user in levels:
                exp = float(levels[user]['exp'])
                level = float(levels[user]['level'])
                name = levels[user]['name']
                if exp > first_exp:
                    first_name = name
                    first_level = level
                    first_exp = exp
                elif exp > second_exp:
                    second_name = name
                    second_level = level
                    second_exp = exp
                elif exp > third_exp:
                    third_name = name
                    third_level = level
                    third_exp = exp
                elif exp > fourth_exp:
                    fourth_name = name
                    fourth_level = level
                    fourth_exp = exp
                elif exp > fifth_exp:
                    fifth_name = name
                    fifth_level = level
                    fifth_exp = exp
                else:
                    pass
            await ctx.send(f"1. {first_name}\n2. {second_name}\n3. {third_name}\n4. {fourth_name}\n5. {fifth_name}")
        except Exception as error:
            await ctx.send(f'```{error}```')

Here is the JSON File in which the data is stored.

{
    "586579525849186315": {
        "name": "MythCraftMC#0963",
        "level": 8,
        "exp": 2174.21875,
        "max_exp": 2562.890625
    },
    "658633474995126282": {
        "name": "Regney#2226",
        "level": 3,
        "exp": 100.0,
        "max_exp": 337.5
    },
    "586579523549196315": {
        "name": "Void#0363",
        "level": 0,
        "exp": 32345,
        "max_exp": 100
    },
    "586579522449186315": {
        "name": "Universal_Kid#0963",
        "level": 4,
        "exp": 350,
        "max_exp": 500
    },
    "586572525844186315": {
        "name": "ThatOneGuy#0453",
        "level": 3,
        "exp": 300,
        "max_exp": 400
    }
}

[ There are no ERRORS ]

Myth
  • 51
  • 1
  • 6

1 Answers1

2

Try going about a different implementation. First, we can make a list to keep track of the users.

userList = []
for user in levels
    exp = float(levels[user]['exp'])
    level = float(levels[user]['level'])
    name = levels[user]['name']
    userList.append([exp, level, name])
userList = sorted(userList, key=lambda x:x[1], reverse=True)

This will fill userList with all users, and sort them based on levels. Then, we can print the first x items in that list.

await ctx.send(f"1. {userList[0][2]}\n2. {userList[1][2]}\n3. {userList[2][2]}\n4. {userList[3][2]}\n5. {userList[4][2]}")

With this, you can get rid of all those variable names, and all those if statements in your code, and make this as dynamic as you want.

Josh
  • 318
  • 2
  • 8
  • Thank you for helping me, I get everything you wrote on the code besides the ```key=lambda x:x[1]``` may I know what that does please? :D – Myth Jul 03 '21 at 02:11
  • 1
    Sure! That tells the sorter how to sort the given data. `key` can be passed a user defined function. Here, we are just telling it that when it goes to compare an item `x`, which is each `[exp, level, name]`, that it should compare by its `x[1]` value. Lambda is essentially an inline, temporary function @MythCraftMC – Josh Jul 04 '21 at 01:00
  • thank so you much for helping me understand this! I now have a clear understanding of the entire code thank you and it works perfectly! :D – Myth Jul 05 '21 at 00:52
  • Awesome!! Now your next step is hooking it up to a database.. :). I'm actually working on a discord bot right now that I just finished hooking up to a MySQL database. If you need help / pointers Id love to help – Josh Jul 05 '21 at 05:08
  • Database? Isn't the data being in a JSON file good enough? I mean it stores all of the users data in there so is there a reason for me to hook it up to a database? – Myth Jul 05 '21 at 16:17
  • Whenever you need get or put data with your json file, you have to reopen it and close it every time. That gets very expensive when the file gets big. Each time you open it, your putting the entire json in memory. With a database, you only retrieve what you want. Another plus is if your program crashes while accessing the json file, that can go bad fast. A databse is much more stable and could easily handle a connection crash. MySQL is free and pretty easy to work with, i highly recommend. – Josh Jul 05 '21 at 16:24
  • Is it possible for me to contact you in some other social platform such as discord for example? I would love it if you could help me with this stuff. – Myth Jul 05 '21 at 20:33