1
\$\begingroup\$

So I've got a Discord bot that will load information about a user's personal charts and display it to them, and one of the commands is to get their leaderboard and show them the most successful songs on their charts. It does this by creating different pages in the embed, and the user can press the reactions to change pages. However, when it comes to generating the embed for each page, I feel like the code I'm using is very messy and could be done in a loop instead, but I'm just not quite sure how to do that, so I'd much appreciate some feedback.

description = []
for i, _ in enumerate(song_name): #song_name is a list of the names of all the songs on the leaderboard
    if i >= 0 and i < 10:
        try:
            description[0] = description[0] + "\n" + str(i+1) + ". **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)"
        except IndexError:
            description.append("1. **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)")
    if i >= 10 and i < 20:
        try:
            description[1] = description[1] + "\n" + str(i+1) + ". **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)"
        except IndexError:
            description.append("11. **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)")
    if i >= 20 and i < 30:
        try:
            description[2] = description[2] + "\n" + str(i+1) + ". **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)"
        except IndexError:
            description.append("21. **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)")
    if i >= 30 and i < 40:
        try:
            description[3] = description[3] + "\n" + str(i+1) + ". **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)"
        except IndexError:
            description.append("31. **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)")
    if i >= 40 and i < 50:
        try:
            description[4] = description[4] + "\n" + str(i+1) + ". **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)"
        except IndexError:
            description.append("41. **" + song_artists[i] + "** - **[" + song_name[i] + "](" + song_link[i] + ")** (" + f"{int(song_points[i]):,}" + " points)")
\$\endgroup\$
2
\$\begingroup\$

Storing songs as objects

You are storing compound information in separate lists, which introduces a lot of bookkeeping and obfuscates the code.

Objects are optimized and used for storing compound structured data like songs.

class Song:
    def __init__(self, name, artist, points):
        self.name = name
        self.artist = artist
        self.points = points

    # for pretty printing the song
    def __str__(self):
        return f"{self.artist} - {self.name} - {self.points}"

songs = [Song("Song1", "Artist1", 100),
         Song("Song2", "Artist2", 200),
         Song("Song3", "Artist3", 150),
         Song("Song4", "Artist4", 354)]

You can follow the official documentation/tutorial or this tutorial from realpython and this one also

Do not reinvent the wheel

python has already a sorted function which can sort a list of objects.

# a lambda is used here just for brevity
# You can use a named function if you want
# this will sort the songs based on the points descending
sorted_songs = sorted(songs, key=lambda song: song.points, reverse=True)

You can then use the sorted list as you wish.

Print all songs sorted by points:

# You do not need to increment the index on each iteration
# enumerate accepts an argument which specifies the start index number
for i, song in enumerate(sorted_songs, start=1):
    print(f"{i}. ** {song}")

which will print

  1. ** Artist4 - Song4 - 354
  2. ** Artist2 - Song2 - 200
  3. ** Artist3 - Song3 - 150
  4. ** Artist1 - Song1 - 100

or you can print specific songs:

# print every 2 songs
# generally print every n song
for i in range(0, len(sorted_songs), 2):
    print(f"{i+1} - {sorted_songs[i]}")
\$\endgroup\$
5
  • \$\begingroup\$ Thanks, the only thing I don't get with this is: how would I add that information to a Discord embed in groups of 10 songs per page, without just doing a bunch of separate if statements for the ranges like I did in my original code? \$\endgroup\$ – Gameskiller01 Jun 8 at 23:06
  • \$\begingroup\$ @Gameskiller01 Discord Documentation on Embed. \$\endgroup\$ – RacketeerHaskeller Jun 8 at 23:14
  • \$\begingroup\$ @Gameskiller01 Tutorials on Discord.py: RealPython, FreeCodeCamp, Discord.py Official Tutorial \$\endgroup\$ – RacketeerHaskeller Jun 8 at 23:27
  • \$\begingroup\$ Thanks, but it wasn't really the Discord embed I was having trouble with, but rather the bunch of separate if statements for the different ranges. I'm sure there must be a way to do it in a loop, but I can't for the life of me figure out how. It probably seems so simple that you wouldn't even think about it, but I can't seem to find anything relating to it. \$\endgroup\$ – Gameskiller01 Jun 8 at 23:29
  • \$\begingroup\$ @Gameskiller01 You are doing the sorting manually yourself, while python provides the sorted function which can sort any list of objects given a key function. Try to reread the answer. \$\endgroup\$ – RacketeerHaskeller Jun 8 at 23:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.