简体   繁体   English

Python - 查找第二小的数字

[英]Python - Find second smallest number

I found this code on this site to find the second largest number:我在这个网站上找到这段代码来找到第二大数字:

def second_largest(numbers):
    m1, m2 = None, None
    for x in numbers:
        if x >= m1:
            m1, m2 = x, m1
        elif x > m2:
            m2 = x
    return m2

Source: Get the second largest number in a list in linear time来源: 在线性时间内获取列表中第二大的数

Is it possible to modify this code to find the second smallest number?是否可以修改此代码以找到第二的数字? So for example例如

print second_smallest([1, 2, 3, 4])
2
a = [6,5,4,4,2,1,10,1,2,48]
s = set(a) # used to convert any of the list/tuple to the distinct element and sorted sequence of elements
# Note: above statement will convert list into sets 
print sorted(s)[1] 

The function can indeed be modified to find the second smallest:该函数确实可以修改为找到第二小的:

def second_smallest(numbers):
    m1 = m2 = float('inf')
    for x in numbers:
        if x <= m1:
            m1, m2 = x, m1
        elif x < m2:
            m2 = x
    return m2

The old version relied on a Python 2 implementation detail that None is always sorted before anything else (so it tests as 'smaller');旧版本依赖于 Python 2 实现细节,即None总是排在其他任何东西之前(因此它测试为“更小”); I replaced that with using float('inf') as the sentinel, as infinity always tests as larger than any other number.余取代了使用float('inf')作为定点,如无穷大总是测试作为比任何其他数量 Ideally the original function should have used float('-inf') instead of None there, to not be tied to an implementation detail other Python implementations may not share.理想情况下,原始函数应该使用float('-inf')而不是None ,以免与其他 Python 实现可能不共享的实现细节相关联。

Demo:演示:

>>> def second_smallest(numbers):
...     m1 = m2 = float('inf')
...     for x in numbers:
...         if x <= m1:
...             m1, m2 = x, m1
...         elif x < m2:
...             m2 = x
...     return m2
... 
>>> print(second_smallest([1, 2, 3, 4]))
2

Outside of the function you found, it's almost just as efficient to use the heapq.nsmallest() function to return the two smallest values from an iterable, and from those two pick the second (or last) value.在您找到的函数之外,使用heapq.nsmallest()函数从迭代中返回两个最小值,并从这两个值中选择第二个(或最后一个)值几乎同样有效。 I've included a variant of the unique_everseen() recipe to filter out duplicate numbers:我已经包含了unique_everseen()配方的一个变体来过滤掉重复的数字:

from heapq import nsmallest
from itertools import filterfalse

def second_smallest(numbers):
    s = set()
    sa = s.add
    un = (sa(n) or n for n in filterfalse(s.__contains__, numbers))
    return nsmallest(2, un)[-1]

Like the above implementation, this is a O(N) solution;和上面的实现一样,这是一个 O(N) 的解决方案; keeping the heap variant each step takes logK time, but K is a constant here (2)!保持堆变量的每一步都需要 logK 时间,但 K 在这里是一个常数 (2)!

Whatever you do, do not use sorting ;无论你做什么,都不要使用排序 that takes O(NlogN) time.这需要 O(NlogN) 时间。

Or just use heapq :或者只是使用heapq

import heapq
def second_smallest(numbers):
    return heapq.nsmallest(2, numbers)[-1]

second_smallest([1, 2, 3, 4])
# Output: 2

As per the Python in-built function sorted根据 Python 内置函数sorted

sorted(my_list)[0]

gives back the smallest number, and sorted(my_list)[1] does accordingly for the second smallest, and so on and so forth.返回最小的数字, sorted(my_list)[1]对第二小的数字进行相应的处理,依此类推。

My favourite way of finding the second smallest number is by eliminating the smallest number from the list and then printing the minimum from the list would return me the second smallest element of the list.我最喜欢的查找第二小的数字的方法是从列表中删除最小的数字,然后从列表中打印最小值将返回列表中第二小的元素。 The code for the task is as below:任务代码如下:

mylist=[1,2,3,4]
mylist=[x for x in mylist if x!=min(mylist)]  #deletes the min element from the list
print(min(mylist))
def second_min_index(ls):
    min_value = min(ls)
    max_value = max(ls)

    # The smallest number changes into the largest.
    for value in ls:
        if value == min_value:
            ls[ls.index(value)] = max_value

    return ls.index(min(ls))

Yes, except that code relies on a small quirk (that raises an exception in Python 3): the fact that None compares as smaller than a number.是的,除了代码依赖于一个小怪癖(在 Python 3 中引发异常): None比较小于数字的事实。

Another value that works is float("-inf") , which is a number that is smaller than any other number.另一个有效的值是float("-inf") ,它是一个比任何其他数字都小的数字。

If you use that instead of None , and just change -inf to +inf and > to < , there's no reason it wouldn't work.如果您使用它而不是None ,并将-inf更改为+inf并将>更改为< ,则没有理由它不起作用。

Edit: another possibility would be to simply write -x in all the comparisons on x , eg do if -x <= m1: et cetera.编辑:另一种可能性是简单地写-x在所有比较x ,例如做if -x <= m1:等等。

Solution that returns second unique number in list with no sort:返回列表中第二个唯一数字且不排序的解决方案:

def sec_smallest(numbers):
    smallest = float('+inf')
    small = float('+inf')
    for i in numbers:
        if i < smallest:
            small = smallest
            smallest = i
        elif i < small and i != smallest:
            small = i
    return small

print('Sec_smallest:', sec_smallest([1, 2, -8, -8, -2, 0]))
 mi= min(input_list)
    second_min = float('inf')
    for i in input_list:
        if i != mi:
            if i<second_min:
                second_min=i
    if second_min == float('inf'):
        print('not present')
    else:
        print(second_min)
             

##input_list = [6,6,6,6,6]
#input_list = [3, 1, 4, 4, 5, 5, 5, 0, 2, 2]
#input_list = [7, 2, 0, 9, -1, 8]
# Even if there is same number in the list then Python will not get confused.

I'd like to add another, more general approach:我想添加另一种更通用的方法:
Here's a recursive way of finding the i-th minimums of a given list of numbers这是查找给定数字列表的第 i 个最小值的递归方法

def find_i_minimums(numbers,i):
    minimum = float('inf')
    if i==0:
        return []
    less_than_i_minimums = find_i_minimums(numbers,i-1)
    for element in numbers:
        if element not in less_than_i_minimums and element < minimum:
            minimum = element
    return less_than_i_minimums + [minimum]

For example,例如,

>>> find_i_minimums([0,7,4,5,21,2,6,1],3) # finding 3 minimial values for the given list
[0, 1, 2]

( And if you want only the i-th minimum number you'd extract the final value of the list ) (如果您只想要第 i 个最小数字,您将提取列表的最终值)

The time-complexity of the above algorithm is bad though, it is O(N*i^2) ( Since the recursion depth is i , and at each recursive call we go over all values in 'numbers' list whose length is N and we check if the minimum element we're searching for isn't in a list of length i-1, thus the total complexity can be described by a geometric sum that will give the above mentioned complexity ).不过,上述算法的时间复杂度很糟糕,它是 O(N*i^2) (由于递归深度是 i ,并且在每次递归调用时,我们都会检查长度为 N 的“数字”列表中的所有值,并且我们检查我们正在搜索的最小元素是否不在长度为 i-1 的列表中,因此总复杂度可以用几何总和来描述,该几何总和将给出上述复杂度)。

Here's a similar but alternative-implementation whose time-complexity is O(N*i) on average.这是一个类似但替代的实现,其时间复杂度平均为 O(N*i)。 It uses python's built-in 'set' data-structure:它使用 python 的内置“set”数据结构:

def find_i_minimums(numbers,i):
    minimum = float('inf')
    if i==0:
        return set()
    less_than_i_minimums = find_i_minimums(numbers,i-1)
    for element in numbers:
        if element not in less_than_i_minimums and element < minimum:
            minimum = element
    return less_than_i_minimums.union(set({minimum}))

If your 'i' is small, you can use the implementations above and then extract how many minimums you want ( or if you want the second minimum, then in your case run the code for i=2 and just extract the last element from the output data-structure ).如果你的“i”很小,你可以使用上面的实现,然后提取你想要的最小值(或者如果你想要第二个最小值,那么在你的情况下运行 i=2 的代码,然后从输出数据结构)。 But if 'i' is for example greater than log(N) , I'd recommend sorting the list of numbers itself ( for example, using mergesort whose complexity is O(N*log(N)) at worst case ) and then taking the i-th element.但是,例如,如果 'i' 大于 log(N) ,我建议对数字列表本身进行排序(例如,在最坏的情况下使用复杂度为 O(N*log(N)) 的归并排序),然后采用第 i 个元素。 Why so?为什么这样? because as stated, the run-time of the algorithm above is not great for larger values of 'i'.因为如上所述,对于较大的“i”值,上述算法的运行时间并不是很好。

You might find this code easy and understandable您可能会发现此代码简单易懂

def secsmall(numbers):
small = max(numbers)
for i in range(len(numbers)):
    if numbers[i]>min(numbers):
        if numbers[i]<small:
            small = numbers[i]
return small

I am assuming "numbers" is a list name.我假设“数字”是一个列表名称。

Find the first and the second smallest numbers in an interger array在整数数组中找到第一个和第二个最小的数字

arr= [1,2,3,4,5,6,7,-1,0,-2,-10]
def minSecondmin(arr,n):
  i=1
  if arr[i-1] < arr[i]:
    f = arr[i-1]
    s = arr[i]
  else:
    f=arr[i]
    s=arr[i-1]

  for i in range(2,n):
    if arr[i]<f:
      s=f
      f = arr[i]
    elif arr[i]<s:
      s=arr[i]
  return f,s

minSecondmin(arr,len(arr))

Here we want to keep an invariant while we scan the list of numbers, for every sublist it must be在这里,我们希望在扫描数字列表时保持不变,对于每个子列表,它必须是

m1<=m2<={all other elements}

the minimum length of a list for which the question (2nd smallest) is sensible is 2, so we establish the invariant examining the first and the second element of the list (no need for magic numbers), next we iterate on all the remaining numbers, maintaining our invariant.问题(第二小)合理的列表的最小长度是 2,所以我们建立不变量检查列表的第一个和第二个元素(不需要幻数),接下来我们迭代所有剩余的数字,保持我们的不变性。

def second_smaller(numbers):
    # if len(numbers)<2: return None or otherwise raise an exception

    m1, m2 = numbers[:2]
    if m2<m1: m1, m2 = m2, m1

    for x in numbers[2:]:
        if x <= m1:
            m1, m2 = x, m1
        elif x < m2:
            m2 = x
    return m2

Addendum附录

BTW, the same reasoning should be applied to the second_largest function mentioned by the OP顺便说一句,同样的推理应该适用于 OP 提到的second_largest函数

l = [41,9000,123,1337]

# second smallest
sorted(l)[1]
123


# second biggest
sorted(l)[-2]
1337

I am writing the code which is using recursion to find the second smallest element in a list.我正在编写使用递归查找列表中第二小的元素的代码。

def small(l):
 small.counter+=1;
 min=l[0];

 emp=[]

 for i in range(len(l)):
    if l[i]<min:
        min=l[i]

 for i in range(len(l)):
    if min==l[i]:
     emp.append(i)

 if small.counter==2:
    print "The Second smallest element is:"+str(min)
 else:
   for j in range(0,len(emp)):

     l.remove(min)

   small(l)
small.counter = 0

list=[-1-1-1-1-1-1-1-1-1,1,1,1,1,1]
small(list)

You can test it with various input integers.您可以使用各种输入整数对其进行测试。

There is a easy way to do .有一个简单的方法可以做到。 First sort the list and get the second item from the list.首先对列表进行排序并从列表中获取第二项。

def solution(a_list):

    a_list.sort()
    print a_list[1]

solution([1, 2, -8, -2, -10])

You can use in built function ' sorted '您可以在内置函数“已排序”中使用

def second_smallest(numbers):

count = 0
l = []
for i in numbers:
    if(i not in l):
        l.append(i)
        count+=1
    if(count==2):
        break

return max(l)

To find second smallest in the list, use can use following approach which will work if two or more elements are repeated.要在列表中找到第二小的,可以使用以下方法,如果重复两个或多个元素,该方法将起作用。

def second_smallest(numbers):
     s = sorted(set(numbers))
     return s[1]

Here is:这是:

def find_second_smallest(a: list) -> int:
    first, second = float('inf')
    for i in range(len(a)):
        if a[i] < first:
            first, second = a[i], first
        elif a[i] < second and a[i] != first:
            second = a[i]
    return second

input: [1, 1, 1, 2]输入:[1, 1, 1, 2]
output: 2输出:2

This code is also works fine, To find the second smallest number in list.此代码也可以正常工作,以查找列表中第二小的数字。 For this code first we have to sort the values in list.对于此代码,首先我们必须对列表中的值进行排序。 after that we have to initialize the variable as second index.之后我们必须将变量初始化为第二个索引。

l1 = [12,32,4,34,64,3,43]
for i in range(0,len(l1)):
       for j in range(0,i+1):
          if l1[i]<l1[j]:
              l1[i],l1[j]=l1[j],l1[i]
min_val = l1[1]
for k in l1:
   if min_val>k:
       break
print(min_val)
def SecondSmallest(x):
    lowest=min(x[0],x[1])
    lowest2 = max(x[0],x[1])
    for item in x:
         if item < lowest:
            lowest2 = lowest
            lowest = item
         elif lowest2 > item and item > lowest:
            lowest2 = item
    return lowest2

SecondSmallest([10,1,-1,2,3,4,5])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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