patternpythonMinor
Students with second lowest grade
Viewed 0 times
withlowestgradestudentssecond
Problem
I solved the Nested List Python challenge on HackerRank.com passing all test cases. Although this problem can likely be solved with a short script with clever one-liners, my approach was instead to solve it in a clean, understandable way in functional style.
Here is a summary of the challenge, see link above for full description:
Print the name(s) of any student(s) having the second lowest grade; if there are multiple students, order their names alphabetically and print each one on a new line.
The first line contains an integer, \$N\$, the number of students.
The \$2N\$ subsequent lines describe each student over \$2\$ lines; the first line contains a student's name, and the second line contains their grade.
I haven't used nested lists much until now and I found myself having to search the internet a good bit for parts of the functions (in particular the
```
def get_students(num_students: int) -> list:
"""Returns a list of names and grades of N students read from stdin
where each name and respective grade is separated by a new line."""
students = []
for s in range(0, num_students):
name = input()
grade = float(input())
students.append([name, grade])
return students
def get_lowest_grade(students: list) -> float:
"""Returns the lowest grade from a list of students[name, grade]."""
lowest_grade_student = min(students, key = lambda x: x[1])
return lowest_grade_student[1]
def get_lowest_grade_students(students: list) -> list:
"""Returns the students with the lowest grade
from a list of students[name, grade]."""
return [s for s in students if s[1] == get_lowest_grade(students)]
def exclude_lowest_grade_students(students: list) -> list:
"""Returns a list of students with the lowest graded students excluded
from a list of students[name, grade]."""
return [s for s in students if s[1] != ge
Here is a summary of the challenge, see link above for full description:
Print the name(s) of any student(s) having the second lowest grade; if there are multiple students, order their names alphabetically and print each one on a new line.
The first line contains an integer, \$N\$, the number of students.
The \$2N\$ subsequent lines describe each student over \$2\$ lines; the first line contains a student's name, and the second line contains their grade.
I haven't used nested lists much until now and I found myself having to search the internet a good bit for parts of the functions (in particular the
get_lowest_grade function) and I would like to improve this code as much as possible. ```
def get_students(num_students: int) -> list:
"""Returns a list of names and grades of N students read from stdin
where each name and respective grade is separated by a new line."""
students = []
for s in range(0, num_students):
name = input()
grade = float(input())
students.append([name, grade])
return students
def get_lowest_grade(students: list) -> float:
"""Returns the lowest grade from a list of students[name, grade]."""
lowest_grade_student = min(students, key = lambda x: x[1])
return lowest_grade_student[1]
def get_lowest_grade_students(students: list) -> list:
"""Returns the students with the lowest grade
from a list of students[name, grade]."""
return [s for s in students if s[1] == get_lowest_grade(students)]
def exclude_lowest_grade_students(students: list) -> list:
"""Returns a list of students with the lowest graded students excluded
from a list of students[name, grade]."""
return [s for s in students if s[1] != ge
Solution
Your code looks nice and is well documented.
Many details can be improved though.
-
-
even though the problem talks about lists, it may be more idiomatic to use a list of tuples instead of a list of list. I'd highly recommend Ned Batchelder's excellent article "Lists vs. Tuples" to know more about this.
-
-
Underscore (
-
Adding a simple
Your code would look like this:
A different algorithm could be written using a different data structure like a dictionnary or a counter.
Many details can be improved though.
-
num_students = int(input()) could be moved in get_students so that your code deals with input in a single place.-
even though the problem talks about lists, it may be more idiomatic to use a list of tuples instead of a list of list. I'd highly recommend Ned Batchelder's excellent article "Lists vs. Tuples" to know more about this.
-
0 as a first argument of range is not needed as it is the default value. So you could rewrite: for s in range(0, num_students): as for s in range(num_students):.-
Underscore (
_) is pretty conventionnal for variable with an used value so you could write: for _ in range(num_students):.-
Adding a simple
print statement in get_lowest_grade shows that the function is called more often that it needs. This is a real issue when you have many students because your algorithm with go through all student for all students. Your algorithm is said to be quadratic or O(n^2). You could retrieve the lowest grade once and for all .Your code would look like this:
def get_students() -> list:
"""Returns a list of names and grades of N students read from stdin
where each name and respective grade is separated by a new line."""
return [('Harry', 37.21), ('Berry', 37.21), ('Tina', 37.2), ('Akriti', 41), ('Harsh', 39),
('Harry', 37.21), ('Berry', 37.21), ('Tina', 37.2), ('Akriti', 41), ('Harsh', 39),
('Harry', 37.21), ('Berry', 37.21), ('Tina', 37.2), ('Akriti', 41), ('Harsh', 39)]
num_students = int(input())
students = []
for s in range(num_students):
name = input()
grade = float(input())
students.append((name, grade))
return students
def get_lowest_grade(students: list) -> float:
"""Returns the lowest grade from a list of students[name, grade]."""
lowest_grade_student = min(students, key = lambda x: x[1])
return lowest_grade_student[1]
def get_students_with_grade(students: list, grade: float) -> list:
"""Returns the students with the lowest grade
from a list of students(name, grade)."""
return [s for s in students if s[1] == grade]
def get_students_without_grade(students: list, grade: float) -> list:
"""Returns a list of students with the lowest graded students excluded
from a list of students(name, grade)."""
return [s for s in students if s[1] != grade]
def get_student_names_sorted_alpha(students: list) -> list:
"""Returns a list of names sorted alphabetically from a list of students[name, grade]"""
names = [s[0] for s in students]
return sorted(names)
def main():
students = get_students()
lowest_grade = get_lowest_grade(students)
students2 = get_students_without_grade(students, lowest_grade)
lowest_grade2 = get_lowest_grade(students2)
second_lowest = get_students_with_grade(students2, lowest_grade2)
for name in get_student_names_sorted_alpha(second_lowest):
print(name)
if __name__ == '__main__':
main()A different algorithm could be written using a different data structure like a dictionnary or a counter.
Code Snippets
def get_students() -> list:
"""Returns a list of names and grades of N students read from stdin
where each name and respective grade is separated by a new line."""
return [('Harry', 37.21), ('Berry', 37.21), ('Tina', 37.2), ('Akriti', 41), ('Harsh', 39),
('Harry', 37.21), ('Berry', 37.21), ('Tina', 37.2), ('Akriti', 41), ('Harsh', 39),
('Harry', 37.21), ('Berry', 37.21), ('Tina', 37.2), ('Akriti', 41), ('Harsh', 39)]
num_students = int(input())
students = []
for s in range(num_students):
name = input()
grade = float(input())
students.append((name, grade))
return students
def get_lowest_grade(students: list) -> float:
"""Returns the lowest grade from a list of students[name, grade]."""
lowest_grade_student = min(students, key = lambda x: x[1])
return lowest_grade_student[1]
def get_students_with_grade(students: list, grade: float) -> list:
"""Returns the students with the lowest grade
from a list of students(name, grade)."""
return [s for s in students if s[1] == grade]
def get_students_without_grade(students: list, grade: float) -> list:
"""Returns a list of students with the lowest graded students excluded
from a list of students(name, grade)."""
return [s for s in students if s[1] != grade]
def get_student_names_sorted_alpha(students: list) -> list:
"""Returns a list of names sorted alphabetically from a list of students[name, grade]"""
names = [s[0] for s in students]
return sorted(names)
def main():
students = get_students()
lowest_grade = get_lowest_grade(students)
students2 = get_students_without_grade(students, lowest_grade)
lowest_grade2 = get_lowest_grade(students2)
second_lowest = get_students_with_grade(students2, lowest_grade2)
for name in get_student_names_sorted_alpha(second_lowest):
print(name)
if __name__ == '__main__':
main()Context
StackExchange Code Review Q#142512, answer score: 6
Revisions (0)
No revisions yet.