0

I wrote this for my beginner class and I don't know how to get the NAME of the SECOND STUDENT with the 2nd highest score. After testing it, I believe the code works for the first student.

I think what I need is to store the highest score in to variable high_score and then the next highest in to second_score and then compare the third score to both the highest and second score. But I am confused on how to get the name of the second highest scoring student.

num_students = int(input("enter number of students: "))
high_score = 0
high_name = ""
second_name = ""
second_score = 0

for i in range(1,num_students + 1):
    if num_students < 2:
        break
    if num_students >= 2:
        name = input("enter student name: ")
        score = int(input("enter student score: "))
    if score > second_score:
        if score > high_score:
            second_score = high_score
            high_score = score
            high_name = name
        elif score < high_score:
            second_score = score
            second_name = name
print()
print("Top Two Students")

print()

print(high_name,"'s score is", high_score)

print(second_name,"'s score is", second_score)
optik404
  • 31
  • 4
  • 1
    You can use a list of two tuples for storing student information. You can sort the list based on scores DESC and then get the first two elements. – gst Oct 17 '21 at 15:54
  • 1
    A few things... After your "if num_students < 2: break" you don't need the next "if num_students >= 2:" . Also, when you determine that the current score is bumping the high score and you update the second_score = high_score, you should add a line to update the second_name at the same time. Other than that, without running your code, it looks like it should work. Also, your last "elif score < high_score:" could just be an "else:" – GaryMBloom Oct 17 '21 at 16:07

3 Answers3

2

In addition to Gary02127's solution, I'd like to point out a few other improvements:

  • You should move if num_students < 2 outside of your loop. It would be enough to check the condition once after the user inputted the number of students.

  • You could also write for i in range(num_students). It doesn't matter if the range starts with 0 or 1 since you are not using i.

  • Also, if you are not using a variable, you could use _ (throwaway variable) instead. See more about for _ in range(num_students) here: What is the purpose of the single underscore "_" variable in Python?.


Instead of:

if score > second_score:
    if score > high_score:
        # ...
    else: 
        # ...

You could also write:

if high_score < score:
    # ...
elif second_score < score:
    # ...

Here is a verbose solution considering suggested improvements:

num_students = int(input("Enter number of students: "))

if num_students < 2:
    exit()

highest_name = None
highest_grade = 0

second_highest_name = None
second_highest_grade = 0

for _ in range(num_students):

    name = input("Enter student's name: ")
    grade = int(input("Enter student's score: "))

    if highest_grade < grade:

        second_highest_name = highest_name
        second_highest_grade = highest_grade
        
        highest_name = name
        highest_grade = grade

    elif second_highest_grade < grade:

        second_highest_name = name
        second_highest_grade = grade

print(highest_name, highest_grade)  # highest grade
print(second_highest_name, second_highest_grade)  # second highest grade

You could also use a list and sorted() (built-in function):

from operator import itemgetter

num_students = int(input("Enter number of students: "))

if num_students < 2:
    exit()
    
grades = []

for _ in range(num_students):

    name = input("Enter student's name: ")
    grade = int(input("Enter student's score: "))

    grades.append((name, grade))
    
grades = sorted(grades, key=itemgetter(1), reverse=True)

print(grades[0])  # highest grade    
print(grades[1])  # second highest grade

You could also use a specialized list such as SortedList (requires external package):

from sortedcontainers import SortedList

num_students = int(input("Enter number of students: "))

if num_students < 2:
    exit()
    
grades = SortedList(key=lambda record: -record[1])

for _ in range(num_students):

    name = input("Enter student's name: ")
    grade = int(input("Enter student's score: "))

    grades.add((name, grade))

print(grades[0])  # highest grade    
print(grades[1])  # second highest grade

Notes:

  • Difference between sorted() and str.sort(). sorted() creates a new sorted list whereas str.sort() modifies the current list.
  • itemgetter(1) is equals to lambda record: record[1].
  • You can install SortedList with: pip install sortedcontainers.
Thomas
  • 8,357
  • 15
  • 45
  • 81
1

Here's a solution based on my previous comments to your original post.

num_students = int(input("enter number of students: "))
high_score = 0
high_name = ""
second_name = ""
second_score = 0

for i in range(1,num_students + 1):
    if num_students < 2:
        break
    # if num_students >= 2:  # don't need this "if" after previous "break"
    name = input("enter student name: ")
    score = int(input("enter student score: "))
    if score > second_score:
        if score > high_score:
            second_score = high_score
            second_name = high_name  # NEW
            high_score = score
            high_name = name
        else:  # simplified to just a plain "else:"
            second_score = score
            second_name = name
print()
print("Top Two Students")

print()

print(high_name,"'s score is", high_score)

print(second_name,"'s score is", second_score)

Notice that simplifying that last "elif ...:" to a simple "else:" also solves a simple bug where entering the current high score again can be ignored and not captured. If you were to run your code as is and use input values "100 80 100", you would find the 2nd high score set to 80 instead of 100.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
GaryMBloom
  • 5,350
  • 1
  • 24
  • 32
  • If possible, could you explain why an "elif" instead of an "else" at the end would cause that to happen? – optik404 Oct 17 '21 at 20:32
  • 1
    @optik404 - sure... when (new) score == high-score, you fail the "if" test and you fail the "else if" test, because the "else if" is checking for score < high_score. But in that instance, score is equal to high_score, so the situation doesn't get handled. You "fall off" the if/else-if tree without handling that condition. By changing the elif to just an else, you catch the state when score is equal to high_score, so it gets processed instead of missed. You could have changed the elif score < high_score: to elif score <= high_score, but that's logically the same as the simple "else" – GaryMBloom Oct 17 '21 at 22:05
  • 1
    @optik404 if/elif trees are great in general, but it's always nice to end with an "else" to make sure that every situation gets handled. One last little blurb... if a < b: ... elif a > b: ... will not handle the case where a == b. And that was one of your bugs. – GaryMBloom Oct 17 '21 at 22:10
0

You can simply store the details in a list. And use list.sort() to sort the values according to the score.

Here is the working code:

num_students = int(input("Enter number of students: "))
scores = []

if num_students < 2:
    print('Number of students less than 2')
    exit()

for i in range(num_students):
    name = input("Enter student's name: ")
    score = int(input("Enter student's score: "))
    scores.append([name, score])

scores.sort(key=lambda details: details[1], reverse=True)

print("Top Two Students")

print()

print(f"{scores[0][0]}'s score is {scores[0][1]}")

print(f"{scores[1][0]}'s score is {scores[1][1]}")