user5405048
user5405048

Reputation:

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?

Upvotes: 4

Views: 3508

Answers (5)

Padraic Cunningham
Padraic Cunningham

Reputation: 180391

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

Upvotes: 1

stian
stian

Reputation: 1987

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.

Upvotes: 1

Nir Alfasi
Nir Alfasi

Reputation: 53525

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

Upvotes: 4

Leb
Leb

Reputation: 15953

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

Upvotes: 3

Mureinik
Mureinik

Reputation: 311018

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]

Upvotes: 0

Related Questions