Problem 1

Analyze the grades of the students.

Here’s an example of the data

111111004  5.0  5.0  6.0
111111005  3.75 3.0  4.0
111111006  4.5  2.25 4.0

Every line represents a grading of a student. It starts with her matriculation number, followed by space-delimited grades (between 1.0 and 6.0, floats). The grades correspond to lectures 1, 2 and 3, respectively.

Provide the function critical which accepts two arguments, bound1 and bound2. The function lists all the students which have “critical” grades. A student should appear only once in the list.

A student is “critical” if the grade for the first lecture is smaller-equal bound1 and the sum of the grades for the lecture 2 and 3 is smaller than bound2.

On the above example, critical(4, 8) gives:

111111005

Provide the function top which lists the students with the best grades. The parameter limit determines the number of the “top” students. If the number of students is less than limit, return the list of all the students.

A student should appear only once in the resulting list. The students are compared based on the sum of the grades in all the three lectures. If the sum of grades is equal for two students, the order in the list is undefined (i.e. does not matter).

On the above example, top(2) might return both the output:

111111004
111111005

and:

111111004
111111006

(Both outputs are valid.)

The parameter limit is always greater than 0. Both bound1 and bound2 are expected in the range [0.0, 100.0].

Data:

ALL_GRADES

List all possible grades.

ALL_GRADES_SET

Provide a set of all possible grades.

GRADING_RE

Express a grading entry for a student as a text.

Classes:

Grade(value)

Represent a grade in Swiss educational system.

Grading(identifier, grade1, grade2, grade3)

Represent the grading of a student.

Functions:

parse(lines)

Parse the grading entries given as lines.

critical(gradings, bound1, bound2)

List critical gradings among the gradings based on bound1 and bound2.

top(gradings, limit)

Find the top limit students among the gradings.

ALL_GRADES = [Decimal('1.00'), Decimal('1.25'), Decimal('1.50'), Decimal('1.75'), Decimal('2.00'), Decimal('2.25'), Decimal('2.50'), Decimal('2.75'), Decimal('3.00'), Decimal('3.25'), Decimal('3.50'), Decimal('3.75'), Decimal('4.00'), Decimal('4.25'), Decimal('4.50'), Decimal('4.75'), Decimal('5.00'), Decimal('5.25'), Decimal('5.50'), Decimal('5.75'), Decimal('6.00')]

List all possible grades.

ALL_GRADES_SET = {Decimal('1.00'), Decimal('1.25'), Decimal('1.50'), Decimal('1.75'), Decimal('2.00'), Decimal('2.25'), Decimal('2.50'), Decimal('2.75'), Decimal('3.00'), Decimal('3.25'), Decimal('3.50'), Decimal('3.75'), Decimal('4.00'), Decimal('4.25'), Decimal('4.50'), Decimal('4.75'), Decimal('5.00'), Decimal('5.25'), Decimal('5.50'), Decimal('5.75'), Decimal('6.00')}

Provide a set of all possible grades.

class Grade(value: Decimal)[source]

Represent a grade in Swiss educational system.

Methods:

__new__(cls, value)

Enforce the grade properties on value.

__le__(other)

Return True if self is smaller than other.

__add__(other)

Add self and other.

static __new__(cls, value: Decimal) Grade[source]

Enforce the grade properties on value.

Requires
  • not value.is_nan()

  • value in ALL_GRADES_SET

__le__(other: Union[Decimal, float, Rational, Grade]) bool[source]

Return True if self is smaller than other.

__add__(other: Union[Decimal, int, Grade]) Decimal[source]

Add self and other.

class Grading(identifier: str, grade1: Grade, grade2: Grade, grade3: Grade)[source]

Represent the grading of a student.

Methods:

__init__(identifier, grade1, grade2, grade3)

Initialize with the given values.

sum_grades()

Sum all grades of the student.

__init__(identifier: str, grade1: Grade, grade2: Grade, grade3: Grade) None[source]

Initialize with the given values.

sum_grades() Decimal[source]

Sum all grades of the student.

Ensures
  • 3 * MIN_GRADE <= result <= 3 * MAX_GRADE

GRADING_RE = re.compile('([a-zA-Z0-9]+) +(1.0|1.25|1.5|1.75|2.0|2.25|2.5|2.75|3.0|3.25|3.5|3.75|4.0|4.25|4.5|4.75|5.0|5.25|5.5|5.75|6.0) +(1.0|1.25|1.5|1.75|2.0|2.25|2.5|2.75|3.0|3.25|3.5|3.75|4.0|4.25|4.5|4.75|5.0|5.25|5.5|)

Express a grading entry for a student as a text.

Note

The function re.Pattern.__repr__ truncates at 200 characters so that the pattern in the docs (based on __repr__ function) is possibly incorrect. See Python issue #13592.

parse(lines: Lines) List[Grading][source]

Parse the grading entries given as lines.

Requires
  • all(GRADING_RE.fullmatch(line) for line in lines)

Ensures
  • len(result) == len(lines)

  • (
        identifiers := [grading.identifier for grading in result],
        len(identifiers) == len(set(identifiers)),
    )[1]
    

    (Unique identifiers)

critical(gradings: List[Grading], bound1: Grade, bound2: Decimal) List[Grading][source]

List critical gradings among the gradings based on bound1 and bound2.

Note that bound1 and bound2 have special semantics. Please consult the text of the problem.

Requires
  • (
            identifiers := [grading.identifier for grading in gradings],
            len(identifiers) == len(set(identifiers))
    )[1]
    

    (Students appear only once)

Ensures
  • (
            identifiers := [grading.identifier for grading in result],
            len(identifiers) == len(set(identifiers))
    )[1]
    

    (Students appear only once)

top(gradings: List[Grading], limit: int) List[Grading][source]

Find the top limit students among the gradings.

Requires
  • limit > 0

  • (
            identifiers := [grading.identifier for grading in gradings],
            len(identifiers) == len(set(identifiers))
    )[1]
    

    (Students appear only once)

Ensures
  • all(
        result[i].sum_grades() >= result[i + 1].sum_grades()
        for i in range(len(result) - 1)
    )
    
  • len(result) == min(limit, len(gradings))

  • (
            identifiers := [grading.identifier for grading in result],
            len(identifiers) == len(set(identifiers))
    )[1]
    

    (Students appear only once)