Reputation: 33
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
Upvotes: 3
Views: 840
Reputation: 755
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()
Upvotes: 3
Reputation: 7582
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)
Upvotes: 1
Reputation: 85
Average the three scores for each person. Place the values into a dictionary (the key will be the person). Call the sorted() method.
Upvotes: 0