Reputation: 179
I have a python function in which I need to find the number in a list 'values' that's closest to a give number 'n' but that's greater than or equal to 'n'.
So far I have this:
def nearest_largest_value2 (n, values):
closest = []
for i in values:
if i == n:
closest = i
elif (i > n) and (i-n < 2):
closest = i
return closest
print(nearest_largest_value2(5, [1,3,4,6,7]))
print(nearest_largest_value2(5, [7,6,4,3,1]))
print(nearest_largest_value2(5, [1,3,4,5,6,7]))
Problem is that I'm getting the answer I want for the first two print statements (6) but I'm getting '6' for the last print statement when I want to get 5.
I'm new to Python but I thought once the first if
clause was satisfied the code would stop.
Upvotes: 1
Views: 2917
Reputation: 418
If you have multiple queries with different numbers, but to the same list, then it's more efficient to first sort the list and then do a binary search on it.
from bisect import bisect_left
values = [7, 6, 4, 3, 1]
values.sort()
def nearest_largest_value2 (n, values):
try:
result = values [bisect_left (values, n)]
except IndexError: # when number is > every element of list
result = None
return result
print (nearest_largest_value2 (5, values)) # 6
print (nearest_largest_value2 (3, values)) # 3
print (nearest_largest_value2 (8, values)) # None
Let p
correspond to length of 'values' list
and q
correspond to the number of inputs 'n'
(or # times nearest_largest_value2
is invoked).
In the stated case, Time Complexity of the previous solution is O(pq)
whereas Time Complexity of the current solution is O((p + q)logp)
.
Upvotes: 0
Reputation: 312219
The condition i-n < 2
is wrong. Instead, you should be checking if the current i
is closer than the current closest
. E.g.:
def nearest_largest_value2 (n, values):
closest = None
for i in values:
if (i >= n) and (closest is None or i < closest):
closest = i
return closest
EDIT:
An alternative way to describe the problem is to find the minimal value that's larger or equal than n
. Describing the problem like that allows for a more "pythonic" oneliner:
def nearest_largest_value2 (n, values):
return min(v for v in values if v >= n)
EDIT2:
As @ekhumoro pointed out, the alternative solution presented in the previous edit will break if values
does not contain any element that is equal to or greater than n
. He also graciously offered a fix for it:
def nearest_largest_value2 (n, values):
min([v for v in values if v >= n] or [None])
Upvotes: 2