简体   繁体   中英

How to find second smallest UNIQUE number in a list?

I need to create a function that returns the second smallest unique number, which means if
list1 = [5,4,3,2,2,1] , I need to return 3, because 2 is not unique.

I've tried:

def second(list1):
    result = sorted(list1)[1]
    return result

and

def second(list1):
    result = list(set((list1)))
    return result

but they all return 2.

EDIT1:

Thanks guys! I got it working using this final code:

def second(list1):
    b = [i for i in list1 if list1.count(i) == 1]
    b.sort()
    result = sorted(b)[1]
    return result

EDIT 2:

Okay guys... really confused. My Prof just told me that if list1 = [1,1,2,3,4] , it should return 2 because 2 is still the second smallest number, and if list1 = [1,2,2,3,4] , it should return 3. Code in eidt1 wont work if list1 = [1,1,2,3,4] . I think I need to do something like:

if duplicate number in position list1[0], then remove all duplicates and return second number. Else if duplicate number postion not in list1[0], then just use the code in EDIT1.

Without using anything fancy, why not just get a list of uniques, sort it, and get the second list item?

a = [5,4,3,2,2,1] #second smallest is 3
b = [i for i in a if a.count(i) == 1]
b.sort()
>>>b[1]
3


a = [5,4,4,3,3,2,2,1] #second smallest is 5
b = [i for i in a if a.count(i) == 1]
b.sort()
>>> b[1]
5

Obviously you should test that your list has at least two unique numbers in it. In other words, make sure b has a length of at least 2.

  1. Remove non unique elements - use sort / itertools.groupby or collections.Counter
  2. Use min - O(n) to determine the minimum instead of sort - O(nlongn). (In any case if you are using groupby the data is already sorted) I missed the fact that OP wanted the second minimum, so sorting is still a better option here

Sample Code

Using Counter

>>> sorted(k for k, v in Counter(list1).items() if v == 1)[1]
1

Using Itertools

>>> sorted(k for k, g in groupby(sorted(list1)) if len(list(g)) == 1)[1]
3

Okay, here usage of set() on a list is not going to help. It doesn't purge the duplicated elements. What I mean is :

l1=[5,4,3,2,2,1]
print set(l1)

Prints

[0, 1, 2, 3, 4, 5]

Here, you're not removing the duplicated elements, but the list gets unique

In your example you want to remove all duplicated elements. Try something like this.

l1=[5,4,3,2,2,1]
newlist=[]
for i in l1:
    if l1.count(i)==1:
    newlist.append(i)
print newlist 

This in this example prints

[5, 4, 3, 1]

then you can use heapq to get your second largest number in your list, like this

print heapq.nsmallest(2, newlist)[-1]

Imports : import heapq , The above snippet prints 3 for you. This should to the trick. Cheers!

Here's a fancier approach that doesn't use count (which means it should have significantly better performance on large datasets).

from collections import defaultdict

def getUnique(data):
    dd = defaultdict(lambda: 0)
    for value in data:
        dd[value] += 1
    result = [key for key in dd.keys() if dd[key] == 1]
    result.sort()
    return result

a = [5,4,3,2,2,1]
b = getUnique(a)
print(b)
# [1, 3, 4, 5]
print(b[1])
# 3

Okay guys! I got the working code thanks to all your help and helping me to think on the right track. This code works:

`def second(list1):
    if len(list1)!= len(set(list1)):
         result = sorted(list1)[2]
        return result
    elif len(list1) == len(set(list1)):
        result = sorted(list1)[1]
        return result`

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM