Search code examples
pythonalgorithmtkinterlistboxrecords

Order items in a listbox in tkinter by an entity value


I have a leaderboard containing information on some scouts. The structure of this information is as follows: ID,forname,surname,points. This information is stored in a file, but isn't in order within the file. I don't want to change this.

I'd like it so that upon updating the listbox (when i call the calcPoints() function), it orders the scouts by the points entity within their record, from largest points to smallest points. Below is the code for my calcPoints() method.

Thanks

def _calcPoints():
        mainWin._leaderboard.delete(0,END)
        with open(tempFileName,'a') as ft:
            for sc in self._Scouts:
                sc._addPoints(-int(sc._getPoints()))
                with open(badgeFile,"r") as fb:
                    lines = fb.readlines()
                    for line in lines:
                        if sc._getID() == line.split(":")[0]:
                            badge = ((line.split(':')[1]).split(',')[0])
                            if badge == "Core":
                                sc._addPoints(5)
                            elif badge == 'Activity':
                                sc._addPoints(1)
                            elif badge == 'Challenge':
                                sc._addPoints(3)
                            elif badge == 'Activity Pack':
                                sc._addPoints(5)
                ft.write(sc.getInfo() + "\n")
        os.remove(leadFile)
        with open(leadFile,"a") as f:
            with open(tempFileName,"r") as ft:
                lines = ft.readlines()
                for line in lines:
                    f.write(line)
        os.remove(tempFileName)
        mainWin.addScoutsLeaderboard()
        return

Solution

  • Just call sorted, sorting by the last element in each line which is the points, using reverse=True will sort from high to low:

    lines = sorted(fb,key=lambda x: float(x.rsplit(":",1)[1]),reverse=True)
    

    Not sure which file the data is in so your file object and delimiter should match your actual file, also if you have a header you will need to add header = next(fb).

    If you are using the values individually you might find the csv module a better fit:

    import csv
    with open(badgeFile,"r") as fb:
        r = csv.reader(fb,delimiter=":")
        lines = sorted(r, key=lambda x: float(x[1]), reverse=True)
        for fid,fname,sname,pnts in lines:
    

    On a side note, you only need to call .readlines() when you actually need a list, if not you can just iterate over the file object.