def make_gradebook():
return []
def make_module_info(module, grade):
module_info = (module,grade)
return module_info
def get_module(module_info):
r
Here's an OO rewrite:
class Module:
def __init__(self, name):
self.name = name
@property
def level(self):
for ch in self.name:
if ch.isdigit():
return int(ch)
class Grade:
grade_marks = {
"A+": 90,
"A-": 80,
"A": 75,
"B+": 70,
"B-": 65,
"B": 60,
"C+": 55,
"C-": 50,
"C": 46
}
def __init__(self, grade):
self.grade = grade
@property
def mark(self):
return Grade.grade_marks[self.grade]
class ModuleGrade:
def __init__(self, module, grade):
self.module = module if isinstance(module, Module) else Module(module)
self.grade = grade if isinstance(grade, Grade ) else Grade(grade)
def __str__(self):
return "{}: {}".format(self.module.name, self.grade.grade)
class StudentGrades:
sortkeys = {
"module": lambda mg: mg.module.name,
"level": lambda mg: mg.module.level,
"grade": lambda mg: -mg.grade.mark # Note: the -ve makes it descending order
}
def __init__(self, name, module_grades = None):
self.name = name
if module_grades is None:
self.module_grades = []
else:
self.module_grades = [mg if isinstance(mg, ModuleGrade) else ModuleGrade(*mg) for mg in module_grades]
def add_grade(self, *args):
if len(args) == 1:
mg = args[0]
if isinstance(mg, ModuleGrade):
self.module_grades.append(mg)
else:
self.module_grades.append(ModuleGrade(*mg))
elif len(args) == 2:
self.module_grades.append(ModuleGrade(*args))
else:
raise ValueError("Bad arguments to StudentGrades.add_grade")
def sort(self, key, reverse=False):
key = StudentGrades.sortkeys.get(key, key)
self.module_grades.sort(key=key, reverse=reverse)
def __str__(self):
return "\n".join([self.name] + [" {}".format(mg) for mg in self.module_grades])
And here's how you use it:
nf = StudentGrades("Norman Foster", [("CS1010S", "A+"), ("CS2020", "A")])
nf.add_grade("MA1101R", "C")
nf.add_grade("SSA1207", "B+")
nf.add_grade("CS4247", "A+")
nf.add_grade("EA5001", "B")
print(nf) # original insertion order
nf.sort("module")
print(nf) # alphabetical by module name
nf.sort("level", reverse=True)
print(nf) # in descending order by level
nf.sort("grade")
print(nf) # descending order by grade
What if you, instead of having multiple if/elif/else
checks, define dictionaries grade->value and sign-value. Then, in the key function grade_to_numeric_marks
just sum up base points per grade and points per sign (+/- or empty).
For example (you may need to tweak values per grade/sign a bit):
points = {'A': 80, 'B': 65}
signs = {'+': 10, '-': -5}
def grade_to_numeric_marks(item):
grade = item[1]
return points.get(grade[0], 50) + signs.get(grade[1:], 0)
def sort_by_grade(gradebook):
return sorted(gradebook, key=lambda x: grade_to_numeric_marks(x), reverse=True)
grades = [('CS1010S', 'A+'), ('MA1101R', 'C'), ('SSA1207', 'B+'), ('CS2020', 'A')]
print sort_by_grade(grades)
prints:
[('CS1010S', 'A+'), ('CS2020', 'A'), ('SSA1207', 'B+'), ('MA1101R', 'C')]
Or, as @clutton mentioned in the comments, define just one dictionary with a mapping grade to points:
{'A+': 95, 'A': 90 ... }
Then, you can simplify the sorting:
points = {'A+': 95, 'A': 90, 'B+': 70, 'B': 65, 'C+': 55, 'C': 50} # need to define all of the possible grades
grades = [('CS1010S', 'A+'), ('MA1101R', 'C'), ('SSA1207', 'B+'), ('CS2020', 'A')]
print sorted(grades, key=lambda x: points.get(x[1]), reverse=True)