简体   繁体   中英

Smallest n numbers from a list

If I have a list list1=[1,15,9,3,6,21,10,11] how do I obtain the smallest 2 integers from that?

min() gives me one number, but what about 2?

You can sort the list and grab the first two elements:

sorted(list1)[:2]

Or, remove the min and find the next min (which should be the quickest solution for large datasets because it requires 3 passes at most):

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

You can import heapq

import heapq

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

print(heapq.nsmallest(2,list1))

The limitation with that is if you have a repeated value let's say l=[1,3,5,1] , the two smallest values will be [1,1] .

Edit 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

From the two, it seems sorting the list is faster for smaller sets.

Edit 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

Thanks to Padraic Cunningham, heapq is faster with larger sets

Using min and two passes over 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)

It list1=[1,1,9,3,6,21,10,11] where the smallest was a dupe, his would still return 1,3 where nsmallest would return 1,1 so that is something to be aware of.

You can also do it in one pass over the list since you have no dupes:

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

Which will be faster than a 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

And if you did actually want to handle dupes:

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

Which will get the two lowest numbers ignoring repeats:

In [48]: list1 = [12, 15, 3, 3, 6, 21, 10, 11]

In [49]: min_two_dupes(list1)
Out[49]: (3, 6)

And runs just as efficiently:

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

you want the n first or 2 first? this is one way to get the 2 first lowest numbers in a list:

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

I am probably deleting my answer as someone suggested while I was writing my answer. This was return the same number multiple times if there are relevant duplicates.

If your list can't contain duplicates, you could use heapq:

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

If it can, you could sort the list and then slice it:

smallest = sorted(list1)[0:2]

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