Reputation: 6589
I am trying to learn Python and I am stuck. Everything went fine until the last function which is the:
def get_class_average(students):
up to that point it all works fine, but there, at the last function, I can't figure out how to make it work. I am trying to get the averages for each student, then calculate the averages of those averages, in other words the "class average" So, I only would like to know the answer for the last function without changing any of the functions before the last one:
lloyd = {
"name": "Lloyd",
"homework": [90.0, 97.0, 75.0, 92.0],
"quizzes": [88.0, 40.0, 94.0],
"tests": [75.0, 90.0]
}
alice = {
"name": "Alice",
"homework": [100.0, 92.0, 98.0, 100.0],
"quizzes": [82.0, 83.0, 91.0],
"tests": [89.0, 97.0]
}
tyler = {
"name": "Tyler",
"homework": [0.0, 87.0, 75.0, 22.0],
"quizzes": [0.0, 75.0, 78.0],
"tests": [100.0, 100.0]
}
def average(numbers):
total = sum(numbers)
return float(total) / len(numbers)
def get_average(student):
homework = average(student["homework"])
quizzes = average(student["quizzes"])
tests = average(student["tests"])
return 0.1 * average(student["homework"]) + 0.3 * average(student["quizzes"]) + 0.6 * average(student["tests"])
def get_letter_grade(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
def get_class_average(students):
results = []
for student in results:
get_average(student)
results.append(student)
average(student)
return results
students = [lloyd,alice,tyler]
print get_class_average(students)
I finally figured out the solution for this one. So, I just want to post the corrected code here below for the last function, get_class_average(students). Now it works:
def get_class_average(students):
results = []
for each in students:
studentavg = float(get_average(each))
results.append(studentavg)
return average(results)
students = [lloyd,alice,tyler]
print get_class_average(students)
Upvotes: 1
Views: 7156
Reputation: 1
This worked for me:
lloyd = {
"name": "Lloyd",
"homework": [90.0, 97.0, 75.0, 92.0],
"quizzes": [88.0, 40.0, 94.0],
"tests": [75.0, 90.0]
}
alice = {
"name": "Alice",
"homework": [100.0, 92.0, 98.0, 100.0],
"quizzes": [82.0, 83.0, 91.0],
"tests": [89.0, 97.0]
}
tyler = {
"name": "Tyler",
"homework": [0.0, 87.0, 75.0, 22.0],
"quizzes": [0.0, 75.0, 78.0],
"tests": [100.0, 100.0]
}
# Add your function below!
def average(numbers):
total = 0.0
total = sum(numbers)
total = float(total) / len(numbers)
return total
def get_average(student):
hweight = 0.1
qweight = 0.3
tweight = 0.6
homework = average(student["homework"])
quizzes = average(student["quizzes"])
tests = average(student["tests"])
total = (homework * hweight) + (quizzes * qweight) + (tests * tweight)
return total
def get_letter_grade(score):
if score >= 90:
return 'A'
elif score < 90 and score >= 80:
return 'B'
elif score < 80 and score >= 70:
return 'C'
elif score < 70 and score >= 60:
return 'D'
else:
return 'F'
def get_class_average(class_list):
results = []
for student in class_list:
running = get_average(student)
results.append(running)
return average(results)
students = [lloyd, alice, tyler]
print "The Average for the class is:\n"
print get_class_average(students)
print
print "Which corresponds to a letter grade of:\n"
print get_letter_grade(get_class_average(students))
Upvotes: 0
Reputation: 1
lloyd = {
"name": "Lloyd",
"homework": [90.0, 97.0, 75.0, 92.0],
"quizzes": [88.0, 40.0, 94.0],
"tests": [75.0, 90.0]
}
alice = {
"name": "Alice",
"homework": [100.0, 92.0, 98.0, 100.0],
"quizzes": [82.0, 83.0, 91.0],
"tests": [89.0, 97.0]
}
tyler = {
"name": "Tyler",
"homework": [0.0, 87.0, 75.0, 22.0],
"quizzes": [0.0, 75.0, 78.0],
"tests": [100.0, 100.0]
}
def average(numbers): total = float(sum(numbers)) return total/len(numbers)
def get_average(student): homework = average(student['homework']) * 0.1 quizzes = average(student['quizzes']) * 0.3 tests = average(student['tests']) * 0.6 return (homework + quizzes + tests)
def get_letter_grade(score): if score > 90 or score == 90: return "A" elif score > 80 or score == 80 and score < 90: return "B" elif score > 70 or score == 70 and score < 80: return "C" elif score > 60 or score == 60 and score < 70: return "D" else: return "F"
students = [lloyd,alice,tyler]
def get_class_average(students): results = [] for student in students: print "student: %s, srednia %s" % (student['name'],get_average(student)) results.append(get_average(student)) print results print get_average(student) return average(results)
print get_class_average(students)
Upvotes: 0
Reputation: 1062
You're not really supposed to take an average of an average, just so you know. I've corrected your code to get it to work correctly. Here it is:
lloyd = {
"name": "Lloyd",
"homework": [90.0, 97.0, 75.0, 92.0],
"quizzes": [88.0, 40.0, 94.0],
"tests": [75.0, 90.0]
}
alice = {
"name": "Alice",
"homework": [100.0, 92.0, 98.0, 100.0],
"quizzes": [82.0, 83.0, 91.0],
"tests": [89.0, 97.0]
}
tyler = {
"name": "Tyler",
"homework": [0.0, 87.0, 75.0, 22.0],
"quizzes": [0.0, 75.0, 78.0],
"tests": [100.0, 100.0]
}
def average(numbers):
total = sum(numbers)
return float(total) / len(numbers)
def get_average(student):
homework = average(student["homework"])
quizzes = average(student["quizzes"])
tests = average(student["tests"])
return 0.1 * average(student["homework"]) \
+ 0.3 * average(student["quizzes"]) \
+ 0.6 * average(student["tests"])
def get_letter_grade(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
def get_class_average(students):
results = []
for student in students:
a = get_average(student)
results.append(a)
return average(results)
students = [lloyd,alice,tyler]
print get_class_average(students)
Since you're new to python, I've taken the better part of an hour or two and rewritten your code to use various features of python, including docstrings, generators, list comprehensions, classes, as well as a map-reduce pattern, and also some new imports as well as how to unit-test a module. I know you said to make minimal changes to your code, but I felt like it would be a discourtesy to you to simply solve your problem and move on. I wanted to give you some snippets, using your example, that I built up and learned while learning python myself.
My example is MUCH longer and larger than yours, and in NO way am I suggesting you take any path beyond the shortest and simplest route, I am merely providing an example. Don't be alarmed when you read this, just go through it and play with it and exploit it to the best of your ability. You may have to keep it ruminating around in your head & filesystem for awhile before it begins to make sense.
If you want to know what all that if __name__ == "__main__":
garbage is about, I suggest you save my code in a file called Student.py
and call import Student
from a python interpreter session. Notice what happens differently :). Also, in the same session, after calling import Student
(from the same directory Student.py
is saved in, of course) type help(Student)
-- I guarantee it will be worth your time.
from __future__ import division # to get rid of having to use float()
from math import floor, log10 # for a helper function
class Student:
"""
A class encapsulating elements of a student object.
Notable properties:
homework_weight(0.1) --> a float multiplying student's homework average
quiz_weight(0.3) --> a float multiplying the student's quiz average
test_weight(0.6) --> a float multiplying the student's test average
delimiter --> a character used to separate fields in __str__
"""
sig_figs = 2
homework_weight = 0.1
quiz_weight = 0.3
test_weight = 0.6
delimiter = '|'
def __init__(self, name, homework, quizzes, tests):
"""
Constructor for the Student object. Parameters are as follows:
name --> a string containing the student's name
homework --> a list of floats containing homework grades
quizzes --> a list of floats containing quiz grades
tests --> a list of floats containing test grades
"""
self.__name = name
self.__homework = homework
self.__quizzes = quizzes
self.__tests = tests
def get_name(self):
""" Returns the current object's name """
return self.__name
def get_homeworks(self):
""" yields a generator object for student's homework grades"""
for i in self.__homework: yield i
def get_quizzes(self):
""" yields a generator object for student's quiz grades"""
for i in self.__quizzes: yield i
def get_tests(self):
""" yields a generator object for student's test grades"""
for i in self.__tests: yield i
@classmethod
def from_dict(cls, student_dict):
"""
Creates a Student object from a dictionary. The dictionary must
contain the following key-value pairs:
'name' : student_name
'homework' : list of floats for homework grades
'quizzes' : list of floats for quiz grades
'tests' : list of floats for test grades
"""
d = student_dict
return cls(d['name'], d['homework'], d['quizzes'], d['tests'])
def __str__(self):
"""
Returns a string representation of the current
object. The representation will be in the form
of the fields separated by the default separator
character (currently '|').
"""
conv = lambda x, d: d.join(map(str, x))
sep = self.delimiter
buff = ''
buff += self.__name + sep
buff += conv(self.__homework, sep) + sep
buff += conv(self.__quizzes, sep) + sep
buff += conv(self.__tests, sep)
return buff
def __repr__(self):
"""
Returns a representation of the current object. In this
case, we will return the same thing as __str__
"""
return str(self)
def to_dict(self):
"""
Returns a dict representation of this object containing
the keys ['name', 'homework', 'quizzes', 'tests'] where
homework, quizzes, and tests are lists of floats.
"""
obj = {}
obj['name'] = self.__name
obj['homework'] = self.__homework
obj['quizzes'] = self.__quizzes
obj['tests'] = self.__tests
return obj
def get_student_average(self, tuplify=False):
"""
This method retrieves the student's class average according
to predefined weighting rules. In this method, we average the
list of scores together for the student's homework, quizzes,
and tests, multiply them by their respective weights, and
sum them together to obtain the final score. See implementation
for more details.
"""
hw = self.__homework
qu = self.__quizzes
ts = self.__tests
if(0 not in map(len, [hw, qu, ts])): #division by zero, bla bla
avg = lambda l: sum(l)/len(l)
avgs = map(avg, [hw, qu, ts])
hwa = avgs[0] * Student.homework_weight
qua = avgs[1] * Student.quiz_weight
tsa = avgs[2] * Student.test_weight
if tuplify is False:
return sum([hwa, qua, tsa])
else:
return (hwa, qua, tsa)
def get_student_averages(self):
"""
This method retrieves the student's class averages according
to predefined weighting rules. In this method, we average the
list of scores together for the student's homework, quizzes,
and tests, multiply them by their respective weights, and return
a set of them as a tuple where (homeworka, quiza, testa)
See implementation for more details.
"""
return self.get_student_averages(tuplify=True)
def get_student_letter_grade(self):
"""
This method takes a student's letter score according to their
average (computed by self.get_student_average()) and fetches
the appropriate letter grade (A through F)
"""
score = self.get_student_average()
if score >= 90: return 'A'
elif score >= 80: return 'B'
elif score >= 70: return 'C'
elif score >= 60: return 'D'
else: return 'F'
@staticmethod
def __get_significant_average(grade_list):
"""
Takes a list of grades and returns an average, does the average
using proper significant figures according to a global variable
grade_list -- a list of floats to average
"""
sigfig = lambda x, n: round(x, -int(floor(log10(x))) + (n - 1))
avg = sigfig(sum(grade_list)/len(grade_list), num_figs)
print '\t\t' + str(avg)
return avg
@staticmethod
def get_class_set(student_list):
"""
Generates a student object from a list of students
and by assembling all the student's grades for each
assignment and then using methods in the Student class
to compute what we need to compute.
"""
# this is REALLY slick. What we're going to do is create a
# generator generators of the student's homework and test
# grades, but for the quizzes we will make regular list of
# lists.
hwg = (x.get_homeworks() for x in student_list)
qwg = [[q for q in y.get_quizzes()] for y in student_list]
twg = (z.get_tests() for z in student_list)
tl = lambda l: [x for x in l]
# ^This is a lambda expression that converts a generator l
# to a list (hence tl)
# since each get_blabla() function returns a generator
# and since each *wg variable is a generator of a generator
# we will eventually get sublists of sublists of sublists
# on and on and on and need to flatten them. Here are three
# ways to do that.
# http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python
hwl = [item for sublist in hwg for item in sublist]
qwl = sum(qwg, [])
twl = reduce(lambda x,y: tl(x)+tl(y), twg)
class_set = Student('class_whole_set', hwl, qwl, twl)
return class_set
if __name__ == "__main__":
lloyd = {
"name": "Lloyd",
"homework": [90.0, 97.0, 75.0, 92.0],
"quizzes": [88.0, 40.0, 94.0],
"tests": [75.0, 90.0]
}
alice = {
"name": "Alice",
"homework": [100.0, 92.0, 98.0, 100.0],
"quizzes": [82.0, 83.0, 91.0],
"tests": [89.0, 97.0]
}
tyler = {
"name": "Tyler",
"homework": [0.0, 87.0, 75.0, 22.0],
"quizzes": [0.0, 75.0, 78.0],
"tests": [100.0, 100.0]
}
slloyd = Student.from_dict(lloyd)
salice = Student(alice['name'], alice['homework'], alice['quizzes'], alice['tests'])
styler = Student.from_dict(tyler)
# YOU COULD DO THIS!
# print 'lloyd dict'
# print '\t' + str(sdlloyd)
#
# print 'alice ctor'
# print '\t' + str(slloyd)
#
# print 'slloyd name: ' + slloyd.to_dict()['name']
# print 'slloyd home: ' + str(map(str, slloyd.to_dict()['homework']))
# print 'slloyd quiz: ' + str(map(str, slloyd.to_dict()['quizzes']))
# print 'slloyd test: ' + str(map(str, slloyd.to_dict()['tests']))
# print 'slloyd avg: ' + str(slloyd.get_student_average())
#
# conv = lambda x: str(map(str, x))
# print 'salice name: ' + salice.get_name()
# print 'salice home: ' + conv(salice.get_homeworks())
# print 'salice quiz: ' + conv(salice.get_quizzes())
# print 'salice test: ' + conv(salice.get_tests())
# print 'salice avg: ' + str(salice.get_student_average())
#
"""Unit test some object obj"""
def unit_test(objname, obj):
conv = lambda x: str(map(str, x))
print str(objname) + ' name: ' + obj.get_name()
print str(objname) + ' home: ' + conv(obj.get_homeworks())
print str(objname) + ' quiz: ' + conv(obj.get_quizzes())
print str(objname) + ' test: ' + conv(obj.get_tests())
print str(objname) + ' avg : ' + str(obj.get_student_average())
print str(objname) + ' let : ' + obj.get_student_letter_grade()
sclss = Student.get_class_set( [slloyd, salice, styler] )
unit_test('sclss', sclss)
unit_test('slloyd', slloyd)
unit_test('salice', salice)
unit_test('styler', styler)
Please let me know if this helps you and if you are confused by any aspect of this code. Welcome to stack overflow :)
Upvotes: 1