How to sort this float list of numerical values in ascending order?

I have been able to import 3 scores (or numbers) for each person in my CSV file and have it work out the average of the three scores for each person but what I need to do next is sort the list of averages shown in the output from high to low. I have searched everywhere and have received 'Float' errors with everything I try.

from collections import defaultdict, deque
with open("highscores.csv", "r+")as file:
    file.seek(0)
    scores = file.readlines()
user_scores = defaultdict(lambda:deque(maxlen=3))
for line in scores:
    name, score = line.rstrip('\n').split(',')
    score = int(score)
    user_scores[name].append(score)

for name in user_scores:
    avg = (user_scores[name])
    x = sorted(avg)
    avg2 = sum(x) / float(len(x))
    print(name, avg2)

Output:

Odis 22.0
Vance 20.0
John 26.0
Marinda 25.0
Shenita 18.0
Marquitta 24.0
Concepcion 17.0
Robby 23.0
Valda 19.0
Ernesto 21.0
Jack 5.0

My CSV file looks like this :

Jack    4
Jack    5
Jack    6
Concepcion  7
Shenita 8
Valda   9
Vance   10
Ernesto 11
Odis    12
Robby   13
Marquitta   14
Marinda 15
John    16
Concepcion  17
Shenita 18
Valda   19
Vance   20
Ernesto 21
Odis    22
Robby   23
Marquitta   24
Marinda 25
John    26
Concepcion  27
Shenita 28
Valda   29
Vance   30
Ernesto 31
Odis    32
Robby   33
Marquitta   34
Marinda 35
John    36

Answers


The line where you sort avg is unnecessary - after all these are the scores of a single person and it doesn't matter in which order you sum them. What you want to do is to sort all the entries once all the averages are calculated, so you need to collect those. If you want them to be sorted according to their averages, use a tuple with the average as the first field, that way sorted will do exactly what you want:

# The list that will hold the pairs of
# average score and name
avgs = []

# Your initial loop
for name in user_scores:
    x = user_scores[name]

    # Just collect the pair
    avgs.append((sum(x) / float(len(x)), name)

# Now sort it
avgs = sorted(avgs)

# Print it
for avg, name in avgs:
    print (name, avg)

However, a much more Pythonesque way of doing it is with list comprehensions:

# A function for the average
def average(lst):
    return sum(lst) / float(len(lst))

# The averages as list comprehension    
avgs = sorted((average(scores), name)
              for name, scores in user_scores.items())

# Print it
for avg, name in avgs:
    print (name, avg)

This assumes that you are using Python 3, for Python 2 use iteritems() or viewitems()


Assuming Python 3…

In your second for loop, you can't possibly get them printed in the desired order if you're printing them while you're still calculating the averages. You need to split it up into two phases.

Calculate the average scores:

avg_user_scores = {
    user: sum(map(float, scores))/len(scores)
    for user, scores in user_scores.items()
}

Then print them, sorted in descending order:

for name, score in sorted(avg_user_scores.items(), key=itemgetter(1), reverse=True):    
    print(name, score)

operator.itemgetter(1) is a way to fetch the second element of a tuple (i.e. lambda t: t[1]) — which is the average score.


The entire program:

from collections import defaultdict, deque
from operator import itemgetter

user_scores = defaultdict(lambda: deque(maxlen=3))
with open('highscores.csv') as file:
    for line in file:
        name, score = line.split(',')
        user_scores[name].append(float(score))
avg_user_scores = {
    user: sum(scores) / len(scores)
    for user, scores in user_scores.items()
}
for name, score in sorted(avg_user_scores.items(), key=itemgetter(1), reverse=True):    
    print(name, score)

Average the three scores for each person. Place the values into a dictionary (the key will be the person). Call the sorted() method.


Need Your Help

Elisp: sleep-for doesn't block when running a test in ert

emacs elisp ert

I'm trying to set up some tests using ert that need to sleep for a background process to proceed. I've tried using sleep-for and accept-process-output. Neither is reliable. Here is a small example....

Translating shape problems : Slow response and sometimes slow movement

animation javafx

As the title says, I would like to know what I'm doing wrong with this. What am I missing and such. The program should be a simple moving game that moves left and right. It does that well but there...