rachitmishra25
rachitmishra25

Reputation: 395

Second smallest element in a list

I have to find the names of student(s) with second smallest grade. My code is working fine some test cases but this one in particular is troubling me:

4 Rachel -50 Mawer -50 Sheen -50 Shaheen 51

Output returned is

Mawer Rachel Sheen

Shaheen has the 2nd smallest grade and should be the output. I am not sure where am I going wrong. Also, I am having trouble with grades as float inputs:

4 Shadab 8 Varun 8.9 Sarvesh 9.5 Harsh 10

Output thrown is Sarvesh when it should be Varun.

import heapq
# range(int(input())):
n = int(input())
builtlist = []
temp= []
names = []
for i in range(0, n):
name = input()
score = float(input())
builtlist.append([name, score])

temp = sorted(builtlist, key = lambda x: x[1])
#minvalue = min(temp, key= lambda x: x[1])

for j in range(len(temp)):
secondsmall = heapq.nsmallest(2, temp)[-1]
if (temp[j][1]==secondsmall[1]):
    names.append(temp[j][0])
list = sorted(names)
print(*list, sep = "\n")

I guess there's some trouble with heapq.nsmallest method I have used but I can't figure out what it is.

Upvotes: 0

Views: 650

Answers (4)

Pavan
Pavan

Reputation: 108

You are going wrong here temp = sorted(builtlist, key = lambda x: x[1]) , heapq.nsmallest(2,temp) returns the n smallest elements in the temp, in your case it will be [50,50,50,51] so it'll return [50, 50] use temp = list(set(temp)) then your code will work.

you can use this code to get the same answer, in case you don't want to use heapq.

# range(int(input())):
n = int(input())
builtlist = []
temp= []
names = []
for i in range(0, n):
    name = input()
    score = float(input())
    builtlist.append([name, score])

temp = list(set([x[1] for x in builtlist]))
secondsmall = sorted(temp)[1]

for j in range(len(builtlist)):
    if (builtlist[j][1]==secondsmall):
        names.append(builtlist[j][0])
list_print = sorted(names)
print(*list_print, sep = "\n")

Upvotes: 1

pylang
pylang

Reputation: 44495

A more common counterpart to heapq in Python is a Counter.

import collections as ct

def second_smallest(lst):
    """Return the second smallest entry."""
    c = ct.Counter()
    for name, score in lst:
        c.update({name:score})
    return c.most_common()[-2]

Application:

builtlist = [["Rachel", -50], ["Mawer", -50], ["Sheen", -50],["Shaheen", 51]]
second_smallest(builtlist)
# ('Sheen', -50)

builtlist = [["Shadab", 8], ["Varun", 8.9], ["Sarvesh", 9.5], ["Harsh", 10]]
second_smallest(builtlist)
# ('Varun', 8.9)

Here are ways to get the least common (or smallest) value using the Counter.most_common() method.

Upvotes: 0

Erich
Erich

Reputation: 2062

There's a lot of things going on here.

First off, stackoverflow does not exist to debug your code and this is a misuse of the website. Please in the future do not do this, and be aware of the

code tags.

Second, heapq.nsmallest() will return the number requested of smallest elements. If two elements are the least and share a value then they both will be returned. Therefore the code is operating as intended.

I would look into python dictionaries, and hashsets for this problem. There exists a more elegant solution.

Upvotes: 0

Darkstarone
Darkstarone

Reputation: 4730

Didn't need to use heapq:

def second_smallest(builtlist):
    # sort on key.
    temp = sorted(builtlist, key = lambda x: x[1])
    second_smallest_group = []
    current_val = 0
    # iterate list comparing i with i + 1
    for i in range(len(temp) - 1):
        current_val = temp[i][1]
        # if in set of first smallest ignore.
        if current_val == temp[i+1][1] and len(second_smallest_group) == 0:
            continue
        # if in second set of smallest add.
        elif current_val == temp[i+1][1] and len(second_smallest_group) > 0: 
            second_smallest_group.append(temp[i+1][0])
        # if changing between sets add first member.
        elif len(second_smallest_group) == 0:
            second_smallest_group.append(temp[i+1][0])
        # if we move to another group break.
        else:
            break
    return second_smallest_group



builtlist = [["Rachel", -50], ["Mawer", -50], ["Sheen", -50],["Shaheen",51]]

print(second_smallest(builtlist))

builtlist = [["Shadab",8], ["Varun", 8.9], ["Sarvesh", 9.5], ["Harsh",10]]

print(second_smallest(builtlist))

Upvotes: 0

Related Questions