2

I am making some code that allows me to choose the closest number from a list, I have managed to do that. However when the closest number is found and its over 'myNumber' I want python to print out the number in the list before it.

For example;

if i were to have a list;

TwoN = [1,2,4,8,16,32,64,128,256,512, 1024, 2048, 4096, 8192]

and

myNumber = 30

I want python to print 16 not 32

This is the code i've done so far...

TwoN = []
for i in range(12):
    TwoN.append(2**i)
print(TwoN)

myNumber = 30
closest = TwoN[0]
for i in range(1, len(TwoN)):
    if abs(TwoN[i] - myNumber) < abs(closest - myNumber):
        closest = TwoN[i];


Sum = myNumber - closest
if Sum < 0:
    closest = TwoN[(i-1)]
    print(closest)
else:
    print(closest)

When myNumber = 30 , the program will output 1024 when i want it to output 16..

any help is appreciated thanks

armallah
  • 101
  • 1
  • 7
  • If you want 30 to print out 16 rather than 32, you don't want to use an algorithm that checks for the smallest absolute difference, you want the smallest difference than's positive. get rid of those `abs` calls, and add a test for `and >= 0`. – abarnert May 01 '18 at 17:57
  • Also, is your list of numbers guaranteed to be sorted like this? If so, you can take advantage of that. – abarnert May 01 '18 at 17:57
  • Related: https://stackoverflow.com/questions/12141150/from-list-of-integers-get-number-closest-to-a-given-value#12141207 https://stackoverflow.com/questions/2566412/find-nearest-value-in-numpy-array https://codereview.stackexchange.com/questions/28207/finding-the-closest-point-to-a-list-of-points https://stackoverflow.com/questions/9706041/finding-index-of-an-item-closest-to-the-value-in-a-list-thats-not-entirely-sort https://stackoverflow.com/questions/36275459/find-the-closest-elements-above-and-below-a-given-number – What May 01 '18 at 17:57

3 Answers3

5

You can use a simple list comprehension with a condition to filter out bigger numbers and return the maximum of the remaining ones:

TwoN = [1,2,4,8,16,32,64,128,256,512, 1024, 2048, 4096, 8192]

def closestLowerNr(data,num):
    """returns from data the biggest number smaller/equal to num""" 
    return max( nr for nr in data if nr <= num) # get max of nr that are smaller/equal

print(closestLowerNr(TwoN,38)) 

The if nr <= number discards anything that is bigger then the wanted number, the max( ... ) gives you the biggest remaining number.


You could also just pass your list one time and get both the highest number below yours as well as the smalles number above yours from it:

TwoN = []
for i in range(12):
    TwoN.append(2**i)
print(TwoN)

myNumber = 32

belowMine = None
aboveMine = None

                     # this is almost always preferable to a range(len(list)) loop                
for nr in TwoN:      # if you really need an index use for i,v in enumerate(list): 
    if not belowMine or nr > belowMine: # get lower bound closest to myNumber
        if nr < myNumber:
            belowMine = nr 
    if not aboveMine or nr < aboveMine: # get upper bound closest to myNumber
        if nr > myNumber:
            aboveMine = nr 

    if nr == myNumber: # exact match, we are done
        belowMine = nr
        aboveMine = nr
        break

if nr == myNumber:       
    print ("Found:",nr)
else:
    print ("Closest numbers to ",myNumber," found:", belowMine,aboveMine)

Output:

[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]
Found: 32
# or 
Closest numbers to  30  found: 16 32
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
3

You can use the bisect module:

import bisect

TwoN = [1,2,4,8,16,32,64,128,256,512, 1024, 2048, 4096, 8192]
myNumber = 30

print(TwoN[bisect.bisect(TwoN, myNumber) - 1])
# 16

bisect.bisect returns an insertion point for myNumber to the right of the value of the list after which it would have to be inserted to keep it in order. So, we just have to substract 1 to get the index of the largest value of the list that is lesser than or equal to myNumber.

Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
3

As @abarnert mentioned if it's sorted it's easy to find

for i in TwoN:
    if i < 30:
        seen = i
    else:
        print seen
        break

>16
eagle
  • 872
  • 5
  • 14