【问题标题】:Smallest n numbers from a list列表中最小的 n 个数字
【发布时间】:2015-10-03 23:27:12
【问题描述】:

如果我有一个列表 list1=[1,15,9,3,6,21,10,11] 我如何从中获取最小的 2 个整数?

min() 给了我一个数字,但是 2 呢?

【问题讨论】:

  • [1,1,2,3,4,5] 应该输出什么?
  • 最好是[1,2],但我的列表中没有重复项。
  • 你关心性能还是简单性?
  • @PasArif,如果你有那么 heapq 将无法工作
  • @JeremyWest 表现

标签: python list


【解决方案1】:

你可以导入heapq

import heapq

list1=[1,15,9,3,6,21,10,11]

print(heapq.nsmallest(2,list1))

限制是如果你有一个重复的值,比如说l=[1,3,5,1],两个最小值将是[1,1]

编辑 1:

In [2]:
    list1=[1,15,9,3,6,21,10,11]

In [3]:

    %timeit sorted(list1)[:2]
    1000000 loops, best of 3: 1.58 µs per loop
In [5]:

    import heapq
    %timeit heapq.nsmallest(2,list1)
    100000 loops, best of 3: 4.18 µs per loop

从两者来看,对于较小的集合,似乎对列表进行排序更快。

编辑 2:

In [14]:

    import random
    list1=[[random.random() for i in range(100)] for j in range(100)]
In [15]:

    %timeit sorted(list1)[:2]
    10000 loops, best of 3: 55.6 µs per loop
In [16]:

    import heapq
    %timeit heapq.nsmallest(2,list1)
    10000 loops, best of 3: 27.7 µs per loop

感谢 Padraic Cunningham,heapq 使用更大的集合更快

【讨论】:

  • nsmallest Leb.他正在寻找最小的。
  • 在一个大列表上运行它,在少数元素上运行不是很丰富
  • @PadraicCunningham 我会试一试并在几秒钟内更新
  • 所以基本上你是说我的解决方案更快,谢谢 :) 顺便说一句,我提供的第二个选项可能更快,因为它需要 3 次通过,sort(通常)需要更多。
  • @alfasin 我不会撒谎,如果它更快那就更快
【解决方案2】:

您可以对列表进行排序并获取前两个元素:

sorted(list1)[:2]

或者,删除最小值并找到下一个最小值(对于大型数据集,这应该是最快的解决方案,因为它最多需要 3 遍):

list1=[1,15,9,3,6,21,10,11]
m1 = min(list1)
list1.remove(m1)
m2 = min(list1)
print m1, m2 # 1 3

【讨论】:

  • 根据我的答案的最后一部分,可以使用 min 或一个 pass 分两次完成。
【解决方案3】:

你想先 n 还是先 2?这是获取列表中前两个最低数字的一种方法:

list1=[1,15,9,3,6,21,10,11]
list1.sort()
twoFirst = list1[:2]
nFirst = list1[:n]

我可能会在我写答案时按照某人的建议删除我的答案。如果有相关的重复,这将多次返回相同的数字。

【讨论】:

    【解决方案4】:

    使用 min 和两次遍历 list1:

    list1=[1,15,9,3,6,21,10,11]
    mn = min(list1)
    mn2 = min(i for i  in list1 if i != mn)    
    print((mn,mn2))
    (1, 3)
    

    list1=[1,1,9,3,6,21,10,11],其中最小的是骗子,他仍将返回 1,3,而 nsmallest 将返回 1,1,因此需要注意。

    您也可以一次性完成,因为您没有受骗者:

    def min_two(lst):
        mn1, mn2 = float("inf"),float("inf")
        for ele in lst:
            if ele < mn1:
                mn1 = ele
                continue
            if ele < mn2:
                mn2 = ele
        return mn1, mn2
    

    这将比heapq.nsmallest 更快:

    In [34]:list1=[random.random()  for j in range(10**5)]
    
    In [35]: timeit  heapq.nsmallest(2,list1)             
    100 loops, best of 3: 11.6 ms per loop
    
    In [36]: timeit min_two(list1)
    100 loops, best of 3: 9.01 ms per loop
    
    In [37]:  %timeit sorted(list1)[:2]
    10 loops, best of 3: 42.2 ms per l
    

    如果你真的想处理骗子:

    def min_two_dupes(lst):
        mn1, mn2 = float("inf"),float("inf")
        for ele in lst:
            if ele < mn1:
                mn1 = ele
                continue
            if ele < mn2 and ele != mn1:
                mn2 = ele
        return mn1, mn2
    

    忽略重复将得到两个最小的数字:

    In [48]: list1 = [12, 15, 3, 3, 6, 21, 10, 11]
    
    In [49]: min_two_dupes(list1)
    Out[49]: (3, 6)
    

    并且运行同样高效:

    In [52]: timeit min_two_dupes(list1)
    100 loops, best of 3: 9.04 ms per loop
    

    【讨论】:

    • 确实,按照你说的,一口气搞定,我太懒了... :)
    【解决方案5】:

    如果您的列表不能包含重复项,您可以使用 heapq:

    from heapq import nsmallest
    list1=[1,15,9,3,6,21,10,11] 
    smallest = nsmallest(2, list1)
    

    如果可以,您可以对列表进行排序,然后对其进行切片:

    smallest = sorted(list1)[0:2]
    

    【讨论】:

    • 两者中,哪一个更快?
    • 尝试更新显然不能,感谢您提供两个选项
    猜你喜欢
    • 2021-09-01
    • 2014-02-21
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-10
    • 2020-05-13
    相关资源
    最近更新 更多