user4477886
user4477886

Reputation:

Sorting a dictionary by average of list in value

I have a dictionary where the keys are names and the values are lists of up to 3 integers (these are the scores of the named people):

classScores={
    'Bob':[1, 6, 3],
    'Jim':[6, 10, 3],
    'Fred':[0, 2]
}

I need to print it sorted by the average of the scores (highest first). I have created a working code to do this:

classAverages={}
for student in classScores:
    classAverages[student]=sum(classScores[student])/len(classScores[student])
for student in sorted(classAverages, key=classAverages.get, reverse=True):
    print(student, "Average:", sum(classScores[student])/len(classScores[student]))

However, I feel this is inefficient as it uses 2 for loops so has to go through every student twice. I am therefore looking for suggestions that incorporate the sorting into the 2nd loop (presumably into its sorted function).


UPDATE: I've gone with a lambda, but I have defined it before the for loop so that I can also use it to print the averages:

classAverages=lambda student: sum(classScores[student]) / len(classScores[student])
for student in sorted(classScores, key=classAverages, reverse=True):
    print(student, "Average:", classAverages(student))

Upvotes: 2

Views: 2561

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122502

You can calculate the average per student in the key function:

for student in sorted(classScores, key=lambda k: sum(classScores[k]) / len(classScores[k]), reverse=True):

Using two loops is only marginally less efficient however; you only increased the fixed cost per student to determine the order. You missed an opportunity to re-use that average in your second loop when displaying the averages:

classAverages={}
for student in classScores:
    classAverages[student] = sum(classScores[student]) / len(classScores[student])

for student in sorted(classAverages, key=classAverages.get, reverse=True):
    print(student, "Average:", classAverages[student])

You could loop over the dictionary items in a generator expression to calculate the averages, sort on those averages, and then display the calculated average all in one operation:

student_averages = ((sum(scores) / len(scores), s) for s, scores in classScores.items())

for average, student in sorted(student_averages, reverse=True):
    print(student, "Average:", average)

The generator produces the data in (average, student) pairs to ease sorting (we now don't need a key to pick out the second value).

Upvotes: 4

Related Questions