2
\$\begingroup\$

I am a beginner in python. This is the Nested Lists problem from HaackerRank.

Given the names and grades for each student in a Physics class of N students, store them in a nested list and print the name(s) of any student(s) having the second lowest grade.

Note: If there are multiple students with the same grade, order their names alphabetically and print each name on a new line.

I want to improve my code with better functions available in python and I want to decrease lines of code.

if __name__ == '__main__':
 scorecard = []
 for _ in range(int(input())):
 name = input()
 score = float(input())
 scorecard.append([name, score])
 scorecard.sort(key = lambda x:x[1])
 names = []
 lowest_score = scorecard[0][1]
 second_lowest = 0
 for i in range(len(scorecard)):
 if scorecard[i][1] > lowest_score and second_lowest == 0:
 second_lowest = scorecard[i][1]
 if second_lowest != 0 and scorecard[i][1] == second_lowest:
 names.append(scorecard[i][0])
 names.sort()
 for name in names:
 print(name)
asked Mar 30, 2020 at 9:56
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$
  1. I'd recommend separating the logic of getting the user input from the logic of building and sorting the nested list.
  2. Your code doesn't build a nested list in a way that's useful for solving the problem; I think what you want is a list of lists of names, where each list of names corresponds to a grade.
  3. Any time you want to group things into buckets (e.g. all the names that go with a grade), it's a good time to use a dictionary!
  4. Using list comprehensions is frequently a good way to express a loop in a shorter way.
  5. Type annotations make it easier to keep track of what your code is doing (and they let you use mypy to catch bugs).

Here's my solution that uses a separate function to build the nested list, using a dictionary as an intermediate step to collect all the names for a given grade. Note that the type annotations tell you exactly where the names (strings) and grades (floats) are going at each step!

from collections import defaultdict
from typing import Dict, List, Tuple
def build_grade_lists(grades: List[Tuple[str, float]]) -> List[List[str]]:
 """
 Given a list of (name, grade) tuples, return a list of names for each grade.
 Each list is sorted, i.e.:
 the top level list is sorted from lowest to highest grade
 each list of names is sorted alphabetically
 """
 grade_lists: Dict[float, List[str]] = defaultdict(list)
 for name, grade in grades:
 grade_lists[grade].append(name)
 return [sorted(grade_lists[grade]) for grade in sorted(list(grade_lists.keys()))]
if __name__ == '__main__':
 scorecard = [(input(), float(input())) for _ in range(int(input()))]
 for name in build_grade_lists(scorecard)[1]:
 print(name)
answered Mar 30, 2020 at 16:12
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 2 small improvements: your function can accept any finite Iterable[Tuple[str, float]], not just lists, and [sorted(names) for _, names in sorted(grade_list.items())] expresses the final result clearer in my opinion. \$\endgroup\$ Commented Mar 30, 2020 at 16:34

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.