Hackerrank problem: https://www.hackerrank.com/challenges/nested-list/problem

So I know answering this will most likely take you off-site so if it’s too much of a hassle don’t bother.

The problem description is the link in the title.
my code is:

if __name__ == '__main__':
    my_names = []
    my_scores = []
    #creating lists to store the inputs, later going to zip them together.
    for _ in range(int(input())):
        name = input()
        score = float(input())
        my_names.append(name)
        my_scores.append(score)

    #sorting the zip list to keep scores and names grouped.
    sorted_zip = sorted(zip(my_scores, my_names), key=lambda x: x[0])

    x = []
    y = []
    #unzipping the list so that the scores can be compared. Was unsure if I could
    # compare tuples.
    
    for i in sorted_zip:
        x.append(i[0])
        y.append(i[1])

    #locating second lowest score and printing the corresponding name. 
    
    
    for i in range(len(x)+1):
        if x[i] < x[i+1]:
            for z in range(i+2,len(x)):
                if x[i+1] == x[z]:
                    print(y[z])
            print(y[i+1])
            break
    #This is putrid code...

So I realize that this isn’t the most elegant code but I could use some assistance on figuring out why it fails the case where the input is:

3
Test1
52
Test2
53
Test3
53

For all other test cases it passes with flying colors. I’m assuming it has to do with the second nested loop and the fact that the list length is only 3 with the second lowest scores being the final two. I don’t know how to fix the indexing without receiving an index error :frowning:

Do i miss something obvious?

i wrote the case you struggle with:

abc = [["Test1", 52], ["Test2", 53], ["Test3", 53]];

then for the most part i used your sorting algorithm:

abc.sort(key=lambda x: x[1])

then you can simple grab the second and third element, get the names and sort them?

apparently not that simple, or i am just simply not paying attention

what a difficult challenge, so many corner cases its difficult to write code which will work if you increase the size of the list.

okay, i normally wouldn’t share my solution, but here you go:

if __name__ == '__main__':
    abc = []
    #creating lists to store the inputs, later going to zip them together.
    for _ in range(int(input())):
        name = input()
        score = float(input())
        abc.append([name, score])
    
    abc.sort(key=lambda x: x[1])
    # get the lowest score
    score = abc[0][1]
    for index, person in enumerate(abc):
        # keep looping over the list until we encounter second lowest score
        if score != person[1]: 
            # if this is last element in the list, just print the name
            if index == len(abc) - 1:
                print(abc[index][0])
            # check if this score and the next score are equal
            elif abc[index][1] == abc[index + 1][1]:
                # if so, sort by name
                result = sorted(abc[index:index + 2], key=lambda x:x[0])
                # and print the names
                print("{}\n{}".format(result[0][0], result[1][0]))
            else:
                # print the name of the person with second lowest score
                print("{}".format(abc[index][0]))
            break;

I am wondering why my code doesn’t perform that function. It needs to be generalized to pass all 10 tests on hackerrank. My code passes 9 out of the 10 and I can’t figure out how to make it pass this particular case.

I could write a separate if statement to catch this specific case but I want it to catch all scenarios on its own merit.

Like I said, I think it has to do with the second loop that’s nested but am unsure how to debug it without giving and indexing error.

1 Like

i tried to see what i could with your code, but i end up writing my own. (see my reply i posted while you where typing :wink: )

i end up catching most corner cases with conditions which i tried to keep generic as possible.

that is the frustrating part about this challenge, then you think you are close because only one test case is missing, but then to solve it a nice way, you have to make changes in which you risk breaking other test cases.

Here is one way to solve the problem; I did my best to document this appropriately. This passes all test cases. If you find anything odd or confusing, please let me know. The call to str in the last part of the method is silly, but I had to add it in order to make my linter happy :slight_smile:.

from operator import itemgetter
from typing import Union

def get_second_lowest(
    grades_list: list[list[Union[str, float]]]
) -> list[str]:
    """ Takes in a list of grades containing a string and float, respectively,
    and retrieves the names for the students who possess the second lowest 
    score. If there are multiple instances of the second lowest score present,
    the names for those students are added to the list of strings returned by
    this method.

    Parameters
    ----------
    grades_list : list[list[Union[str, float]]]
        A list of lists containing the name and the score for that particular
        student, respectively.

    Returns
    -------
    list[str]
        A list of strings representing the names of the students that have the
        second lowest score in the list of grades.
    """

    # Sort the grades using `itemgetter`. We use `sorted` and
    # `itemgetter` so we can sort the values based on both indexes.
    # This will sort the list how we need it to perform the rest of
    # the operations.

    sorted_grades = sorted(grades_list, key=itemgetter(1, 0))

    # Using a set comprehension, we can create a set of values where
    # no score value is duplicated; the second item in the list is
    # always the second lowest score value.

    grades_set = sorted(list({n[1] for n in sorted_grades}))

    # Using a list comprehension, we can return a list of names that
    # where the second lowest score matches the second index of the
    # nested list contained inside of `sorted_grades`.

    return [str(n[0]) for n in sorted_grades if n[1] == grades_set[1]]

if __name__ == '__main__':
    grades_list = [[input(), float(input())] for n in range(int(input()))]
    print("\n".join(get_second_lowest(grades_list)))