4Python Return closest number above and below given xPython Return closest number above and below given x

```
import bisect
def find_nearest(arr,value):
arr.sort()
idx = bisect.bisect_left(arr, value)
if idx == 0:
return None, arr[idx]
elif idx == len(arr):
return arr[idx - 1], None
elif arr[idx] == value:
return arr[idx], arr[idx]
else:
return arr[idx - 1], arr[idx]
array = [1, 5, 7, 9, 10, 11, 14, 15]
print(find_nearest(array, 0))
print(find_nearest(array, 4))
print(find_nearest(array, 8))
print(find_nearest(array, 10))
print(find_nearest(array, 20))
```

Output:

```
(None, 1)
(1, 5)
(7, 9)
(10, 10)
(15, None)
```

Source: link

This answer based on `@Mark Tolonen`

hint about `bisect`

Let's say that you need to append one number on every iteration but initial array is the same.

All elements in array should be unique. Initial array may be not sorted.

```
import bisect as b
init_array = [5, 9, 10, 11, 14, 15, 1, 7]
init_array.sort()
numbers_to_append = [22, 4, 12, 88, 99, 109, 999, 1000, 1001]
numbers_to_check = [12, 55, 23, 55, 0, 55, 10, 999]
for (_, n) in enumerate(numbers_to_check):
# get index of closer right to below
i = b.bisect_left(init_array, n)
# get above
if i >= (len(init_array)):
above = None
else:
if init_array[i] == n:
try:
above = init_array[i + 1]
except IndexError:
above = None
else:
above = init_array[i]
# get below
below = init_array[i - 1] if i - 1 >= 0 and init_array[i - 1] - n < 0 else None
print('---------')
print('array is', init_array)
print('given x is', n)
print('below is', below)
print('above is', above)
print('appending', numbers_to_append[_])
# check if number trying to append doesn't exists in array
# WARNING: this check may be slow and added only for showing that we need to add only unique numbers
# real check should be based on real conditions and numbers that we suppose to add
i_to_append = b.bisect_left(init_array, numbers_to_append[_])
if numbers_to_append[_] not in init_array[i_to_append:i_to_append+1]:
init_array.insert(i_to_append, numbers_to_append[_])
```

output:

```
---------
array is [1, 5, 7, 9, 10, 11, 14, 15]
given x is 12
below is 11
above is 14
appending 22
---------
array is [1, 5, 7, 9, 10, 11, 14, 15, 22]
given x is 55
below is 22
above is None
appending 4
---------
array is [1, 4, 5, 7, 9, 10, 11, 14, 15, 22]
given x is 23
below is 22
above is None
appending 12
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22]
given x is 55
below is 22
above is None
appending 88
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88]
given x is 0
below is None
above is 1
appending 99
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88, 99]
given x is 55
below is 22
above is 88
appending 109
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88, 99, 109]
given x is 10
below is 9
above is 11
appending 999
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88, 99, 109, 999]
given x is 999
below is 109
above is None
appending 1000
```

Source: link

I have a DataFrame that contains the data shown below:

soc [%] r0 [ohm] tau1 [s] tau2 [s] r1 [ohm] r2 [ohm] c1 [farad] c2 [farad] 0 90 0.001539 1725.035378 54.339882 0.001726 0.001614 999309.883552 33667.261120 1 80 0.001385 389.753276 69.807148 0.001314 0.001656 296728.345634 42164.808208 2 70 0.001539 492.320311 53.697439 0.001139 0.001347 432184.454388 39865.959637 3 60 0.001539 656.942558 63.233445 0.000990 0.001515 663400.436465 41727.472274 4 50 0.001539 296.080424 53.948112 0.000918 0.001535 322490.860387 35139.878909 5 40 0.001539 501.978979 72.015509 0.001361 0.001890 368919.408585 38100.665763 6 30 0.001539 585.297624 76.972464 0.001080 0.001872 542060.285388 41114.220492 7 20 0.001385 1308.176576 60.541172 0.001426 0.001799 917348.863136 33659.124096 8 10 0.001539 1194.993755 57.078336 0.002747 0.001851 435028.073957 30839.130201Given a value z, I want to select a row in the data frame where soc [%] is closest to z. The code below demonstrates my current approach.

import pandas as pd import time def rc_params(df, z): if z > 90: params = df.loc[0] elif 80 < z <= 90: params = df.loc[0] elif 70 < z <= 80: params = df.loc[1] elif 60 < z <= 70: params = df.loc[2] elif 50 < z <= 60: params = df.loc[3] elif 40 < z <= 50: params = df.loc[4] elif 30 < z <= 40: params = df.loc[5] elif 20 < z <= 30: params = df.loc[6] elif 10 < z <= 20: params = df.loc[7] else: params = df.loc[8] r0 = params['r0 [ohm]'] tau1 = params['tau1 [s]'] tau2 = params['tau2 [s]'] r1 = params['r1 [ohm]'] r2 = params['r2 [ohm]'] return r0, tau1, tau2, r1, r2 start = time.time() z = 20 df = pd.read_csv('results/soc_rc.csv') r0, tau1, tau2, r1, r2 = rc_params(df, z) end = time.time() print(f""" z = {z} r0 = {r0:.4f} tau1 = {tau1:.4f} tau2 = {tau2:.4f} r1 = {r1:.4f} r2 = {r2:.4f} run time = {end - start:.4g} s """)Results from the above code give:

z = 20 r0 = 0.0014 tau1 = 1308.1766 tau2 = 60.5412 r1 = 0.0014 r2 = 0.0018 run time = 0.002264 sNot sure if this will help, but I'm using this to find nearest in a sorted column: (time series stuff)

result_index = df['col_to_search'].sub(search_value).abs().idxmin()Adapting from here would be a cleaner way to do what you want.

params = df.iloc[(df['soc [%]']-z).abs().argsort()[:1]]

Source: link

Assuming that your array is not sorted, you will be indeed forced to scan the entire array. But if it is sorted you can use a binary search approach that will run in

`O(log(n))`

, something like this: