3
\$\begingroup\$

I'm teaching myself programming.

I would like to know how I could make this Python3 could more flexibile, for example if I wanted to find students with the 3rd lowest grade, or the lowest, or any other value. Based on this piece of code (that it took me awhile to fathom out) I'm not convinced Python is the best tool for this task. It uses the data structure it does because the task brief I was working on requested that I use nested lists.

#! /usr/bin/env python3

# Number of student records to expect
n = int(input())

# Take inp of n student records, store in format [[name, score], [name, score], ...]
students = [[input(), float(input())] for studentrecord in range(n)]

# Sort records by score, ascending. Using float else defaults to lexicographical order.
students.sort(key=lambda studentrecord: float(studentrecord[1]))

# Get the lowest mark achieved
lowest_mark = students[0][1]

# Get ind of second lowest scoring student
ind = 0
while students[ind][1] == lowest_mark:
    ind += 1

# Get the second lowest mark achieved
second_lowest_mark = students[ind][1]

second_lowest_scoring_students = []

# Accumulate list of second lowest scoring students.
while students[ind][1] == second_lowest_mark:
    second_lowest_scoring_students.append(students[ind][0])
    ind += 1
    if ind == n: # If iteration reaches the end of the list of records, end.
        break

# Sort name/s alphabetically.
second_lowest_scoring_students.sort()

# Send results to stdout.
for student_name in second_lowest_scoring_students:
    print(student_name)
\$\endgroup\$
  • 1
    \$\begingroup\$ pandas is a module you can import to make your life easier in this case. \$\endgroup\$ – Ev. Kounis Jul 15 '16 at 13:04
  • \$\begingroup\$ Thanks very much :), I've seen pandas somewhere before but I can't remember where, will read up on it \$\endgroup\$ – Duncan Betts Jul 15 '16 at 16:50
  • 1
    \$\begingroup\$ Sounds like a hackerrank problem. This might be of interest. \$\endgroup\$ – 409_Conflict Jul 15 '16 at 18:08
4
\$\begingroup\$

Your code seems reasonable, if you consider the use of nested lists to be a requirement. It is clearly written enough that you could just omit most or even all of the comments. You could simplify the determination of the second-lowest score using itertools.groupby().

It is customary to use _ as the name of a "throw-away" variable whose value will never be used, such as studentrecord in

students = [[input(), float(input())] for studentrecord in range(n)]

I wouldn't blame Python for being the wrong language for this challenge. Rather, the advice to use nested lists is poor. This problem would be much more naturally solved if you classified the students by their score. That would be easily accomplished using a dictionary, specifically a defaultdict(list).

from collections import defaultdict

students_by_score = defaultdict(list)
for _ in range(int(input())):
    name = input()
    score = float(input())
    students_by_score[score].append(name)

second_lowest_score = sorted(students_by_score)[1]
for student_name in sorted(students_by_score[second_lowest_score]):
    print(student_name)

If I had to use a nested list in the solution, I'd still convert it to a dictionary first. =)

Furthermore, I would consider a list of tuples to be more appropriate than a list of lists for this situation. A list is good for homogeneous data of variable length. A tuple, on the other hand, has a connotation of being a fixed number of elements, possibly of different data types. (Tuples in Python also happen to be immutable.) Although the nested list works just fine, and the Python interpreter doesn't care, I would choose tuples here because they would convey the right connotation.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.