'Nested List HackerRank Issue in Passing all 10 Tests
Given the names and grades for each student in a Physics class of 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.
Input Format
The first line contains an integer, , the number of students. The subsequent lines describe each student over lines; the first line contains a student's name, and the second line contains their grade.
Constraints
There will always be one or more students having the second lowest grade.
Output Format
Print the name(s) of any student(s) having the second lowest grade in Physics; if there are multiple students, order their names alphabetically and print each one on a new line.
Sample Input
5
Harry
37.21
Berry
37.21
Tina
37.2
Akriti
41
Harsh
39
Sample Output
Berry
Harry
Here is my code to the problem:
if __name__ == '__main__':
list = []
for _ in range(int(input())):
name = input()
score = float(input())
#list = []
list.append([name, score])
#print(list)
list.sort(key = lambda x: float(x[1]))
#print(list)
new_lst = []
for i in range(len(list)):
for j in range(1):
if list[i][1] == list[1][1]:
new_lst += [list[i][0]]
#print(new_lst)
sorted_lst = sorted(new_lst)
#print(sorted_lst)
for student in sorted_lst:
print(student)
Code failed for 2 out of 10 test cases (test 2 and 3). Here are the test 2 and 3 cases:
Sample Input (Test 2)
5
Harsh
20
Beria
20
Varun
19
Kakunami
19
Vikas
21
Sample Output (Test 2)
Beria
Harsh
Sample Input (Test 3)
4
Rachel
-50
Mawer
-50
Sheen
-50
Shaheen
51
Sample Output (Test 3)
Shaheen
However, I can't figure out why those 2 test cases didn't work since I thought I covered the boundary test cases well enough. My code did pass 8 of the 10 tests though including the first test case above.
Is there something I am missing?
Edit
I figured out a way to pass the remaining test cases (my revised code):
if __name__ == '__main__':
lst = []
for _ in range(int(input())):
name = input()
score = abs(float(input()))
#lst = []
lst.append([name, score])
#print(lst)
lst.sort(key = lambda x: float(x[1]))
#print(lst)
#lst.remove(min(lst))
#print(lst)
new_lst = []
min_mark = lst[0][1]
count = 0
for i in range(len(lst)):
if min_mark == lst[i][1]:
count = count+1
if count > 1:
for j in range(count - 1):
lst.pop(0)
#print(lst)
for i in range(len(lst)):
for j in range(1):
if lst[i][1] == lst[1][1]:
new_lst += [lst[i][0]]
#print(new_lst)
sorted_lst = sorted(new_lst)
#print(sorted_lst)
for student in sorted_lst:
print(student)
What do you think of this final code? Is it good enough? Or should I shorten it?
Solution 1:[1]
One possible implementation using heap and itertools.groupby:
from heapq import heappush, heappop
from itertools import groupby
n = int(input())
heap = []
for i in range(n):
name = input()
score = float(input())
heappush(heap, (score, name))
grouper = groupby((heappop(heap) for _ in range(len(heap))), key=lambda k: k[0])
next(grouper) # skip lowest score
print(*(v for _, v in next(grouper)[1]), sep="\n") # print second lowest group
Solution 2:[2]
Reusing most of your existing code, you can solve it more 'step-by-step' like this:
if __name__ == '__main__':
score_list = []
for _ in range(int(input())):
name = input()
score = float(input())
score_list.append([name, score])
score_list.sort(key = lambda x: float(x[1]))
min_score = score_list[0][1]
# remove the minimum score entries
score_list = list(filter(lambda x: x[1] != min_score, score_list))
second_min_score = score_list[0][1] #since the minimum were removed
# keep the second minimum score entries
score_list = list(filter(lambda x: x[1] == min_score, score_list))
# sort the names alphabetically, if there are multiple entries
score_list.sort(key = lambda x: x[0])
for student in score_list:
print(student[0])
Solution 3:[3]
I'd probably take a simple, three-steps approach.
(Note: I've changed list to list_ since using a reserve keyword usually isn't a good idea.)
Assuming your student lists look like this:
Test 2:
[
['Harsh', '20'],
['Beria', '20'],
['Varun', '19'],
['Kakunami', '19'],
['Vikas', '21']
]
Test 3:
[
['Rachel', '-50'],
['Mawer', '-50'],
['Sheen', '-50'],
['Shaheen', '51']
]
1 - Get the total minimum grade
min_grade = min([list_[i][1] for i in range(len(list_))])
2 - Get the minimum grade that is above our initial lowest grade
next_min_grade = min([list_[i][1] for i in range(len(list_)) if list_[i][1] > min_grade])
3 - Generate list of students with next-lowest grade
next_min_students = [list_[i][0] for i in range(len(list_)) if list_[i][1] == next_min_grade]
You can output with the .join() function and newline (\n) character.
print("\n".join(next_min_students))
Test 2:
Harsh
Beria
Test 3:
Shaheen
Solution 4:[4]
I did this question with two implementations in hacker rank.
- First Implementation using
set
if __name__ == '__main__':
stu_list = [[input(), float(input())] for _ in range(int(input()))]
# _[1] : it takes 1st arguments from all nested lists of stu_list
# last [1] takes secondLowestGrade from set
# sec_lowest_grade = sorted(set(_[1] for _ in stu_list))[1]
print("\n".join(sorted(_[0] for _ in stu_list if _[1] == sorted(set(_[1] for _ in stu_list))[1])))
- Second Implementation without using set
from operator import itemgetter
main_lst = []
for _ in range(int(input())):
main_lst.append([input(),float(input())])
main_lst.remove(min(main_lst,key=itemgetter(1)))
temp_list = []
min_list = min(main_lst,key=itemgetter(1))
for i in main_lst:
if i[1] == min_list[1]:
temp_list.append(i)
for i in sorted(temp_list,key=itemgetter(0)):
print(i[0])
- @DewMan I submitted both the solution and it passed through all the test cases. Just try and let me inform if it will work for you.
Solution 5:[5]
I think you are satisfied with the answers, but I have a slightly different solution and I would like to share. Hope that helps too. in Python3:
if __name__ == '__main__':
n = int(input())
students = [[input(), float(input())] for _ in range(n)]
students.sort(key=lambda gr: (gr[1], gr[0]))
grade = [i[1] for i in students]
names = [i[0] for i in students]
seclowValue = sorted(set(grade))[1]
for x in range(len(grade)):
if grade[x] == seclowValue:
print(names[x])
Solution 6:[6]
Following code works for solving the problem too!
if __name__ == '__main__':
l= []
l2 = []
for _ in range(int(input())):
name = input()
score = float(input())
l.append(list([name, score]))
#print(l)
lsort = sorted(l, key=lambda x: (x[1], x[0]))
#print(lsort)
# following only addresses only the max value of all and ot
# a list of those with max scores
for i in range(len(lsort)):
if lsort[i][1] != max(lsort, key=lambda x: x[1])[1]:
#print(lsort[i])
l2.append(lsort[i])
#print(l2)
for i in range(len(l2)):
if l2[i][1] == max(l2, key=lambda x: x[1])[1]:
print(l2[i][0])
Solution 7:[7]
if name == 'main':
mark = set()
student = []
for _ in range(int(input())):
name = input()
score = float(input())
mark.add(score)
student.append([name,score])
mark = sorted(mark)[1]
print('\n'.join([a for a,b in sorted(student) if b == mark]))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Andrej Kesely |
| Solution 2 | DaveIdito |
| Solution 3 | |
| Solution 4 | Deep Dalsania |
| Solution 5 | Bruno Raphaell |
| Solution 6 | aagar2003 |
| Solution 7 | Rajan Pandey |
