Arctic
Arctic

Reputation: 33

Top 5 scores using csv

I am having difficulty with presenting the top 5 scores from a csv file. This is my current code:

def leaderboards():
    with open('userData.csv', 'r') as data:
        reader = csv.reader(data)
        for idx, row in enumerate(reader):
            print('{} | {} | {}'.format(str(idx), row[0], row[2]))  

This is what I currently get:

>>> leaderboards()
0 | Name | Score
1 | Ryan | 3
2 | Liam | 12
3 | Steve | 3
4 | Donald | 3
5 | Alan | 3
6 | Harry | 1

There are two main elements that I would like to implement but don't know how. They are to sort the score so that the highest score is at the top, and to limit the number of players the leaderboards show to 5.

Current code:

    with open('userData.csv', 'r') as data:
                reader = csv.DictReader(data)
                newList = sorted(reader, key=lambda row: row['Score'],
reverse=False)[0:5]
                print ('  | Name | Score')
                for i, r in enumerate(newList):
                    print('{} | {} | {}'.format(str(i), r['Name'], r['Score']))

Current result:

  | Name | Score
0 | Liam | 12
1 | Harry | 2
2 | Ryan | 3
3 | Steve | 3
4 | Donald | 3

It works for the most part, however, the 2 is higher up than the 3. I'm not really sure why but maybe you might realise something. Once again, thank you so much and I'm sorry that I'm just asking so much but this is out of my league in terms of coding knowledge. :D

Upvotes: 0

Views: 3128

Answers (1)

tlm
tlm

Reputation: 1022

If you're trying to sort on the last element of each row, the blank space is throwing an error. Also, I think you're script will also consider the header row for sorting, so if you're not looking to consider that, you should skip that row when sorting.

If you want to print out the score the way you want according to your file structure, you could do something like the following:

with open('...file name here...', 'r') as data: reader = csv.reader(data) for idx, row in enumerate(reader): print '{} | {} | {}'.format(str(idx), row[0], row[2])

That will print things out line by line according to how you've indexed your csv. Since you have a header row, I would also suggest that you take a look at DictReader within the Python csv module. That way you won't have to rely on index position in the future.

Also, if you've having issues with extra lines in csv's, take a look at this answer.

Update for sorting based on the request in comments:

To sort your reader you can just use lambda based on the appropriate key in your csv columns. Assuming that Score is the column you wish to sort on and that Score is of index 2, you can do:

newList = sorted(reader, key=lambda row: row[2], reverse=True)

That will give you a sorted list in descending order by the 2nd index. Remove reverse=True for an ascending list order.

Then, if you want to take only the first five entries, you can just slice the list:

slicedList = newList[0:5]

Then, you can print out your list as usual.

Update 2 to accommodate second request:

with open('...name of your file...', 'r') as data:
    reader = csv.reader(data)
    newList = sorted(reader, key=lambda row: row[2], reverse=True)[0:5]
    for i, r in enumerate(newList):
        print('{} | {} | {}'.format(str(i), r[0], r[2]))

The above code assumes (from your original csv file) that r[0] is the "Name" column and r[2] is the "Score" column.

Also, as an alternative, you could use csv.DictReader just in case your column headers change index. The alternative code would be something like:

with open('...your file name here...', 'r') as data:
    reader = csv.DictReader(data)
    #### COMMENTING THIS OUT in favor of the newList below
    # newList = sorted(reader, key=lambda row: row['Score'], reverse=True)[0:5]
    ##### EDIT to evaluate the Score as an int()
    # cast row['Score'] to an int() below so that sorted() treats the row like and int rather than str
    newList = sorted(reader, key=lambda row: int(row['Score']), reverse=True)[0:5]
    print ('  | Name | Score')
    for i, r in enumerate(newList):
        print('{} | {} | {}'.format(str(i), r['Name'], r['Score']))

Upvotes: 1

Related Questions