Search code examples
pythonfloating-pointintervalsinterval-arithmetic

Iterate through ranges and return those not in any range?


I have a list of floats.

values = [2.3, 6.4, 11.3]

What I want to do is find a range from each value in the list of size delta = 2, then iterate through another range of floats and compare each float to each range, then return the floats that do not fall in any ranges.

What I have so far is,

not_in_range =[]
for x in values:
        pre = float(x - delta)
        post = float(x + delta)
        for y in numpy.arange(0,15,0.5):
                if (pre <= y <= post) == True:
                        pass
                else:
                        not_in_range.append(y)

But obviously, this does not work for several reasons: redundancy, does not check all ranges at once, etc. I am new to coding and I am struggling to think abstractly enough to solve this problem. Any help in formulating a plan of action would be greatly appreciated.

EDIT For clarity, what I want is a list of ranges from each value (or maybe a numpy array?) as

[0.3, 4.3]
[4.4, 8.4]
[9.3, 13.3]

And to return any float from 0 - 15 in increments of 0.5 that do not fall in any of those ranges, so the final output would be:

not_in_ranges = [0, 8.5, 9, 13.5, 14, 14.5] 

Solution

  • To generate the list of ranges, you could do a quick list comprehension:

    ranges = [[x-2, x+2] for x in values]
    
    ## [[0.3, 4.3], [4.4, 8.4], [9.3, 13.3]]
    

    Then, to return any float from 0 to 15 (in increments of 0.5) that don't fall in any of the ranges, you can use:

    not_in_ranges = []
    for y in numpy.arange(0, 15, 0.5):      # for all desired values to check
      if not any(pre < y and y < post for pre, post in ranges):
        not_in_ranges.append(y)             # if it is in none of the intervals, append it
    
    ## [0.0, 8.5, 9.0, 13.5, 14.0, 14.5]
    

    Explanation: This loops through each of the possible values and appends it to the not_in_ranges list if it is not in any of the intervals. To check if it is in the intervals, I use the builtin python function any to check if there are any pre and post values in the list ranges that return True when pre < y < post (i.e. if y is in any of the intervals). If this is False, then it doesn't fit into any of the intervals and so is added to the list of such values.


    Alternatively, if you only need the result (and not both of the lists), you can combine the two with something like:

    not_in_ranges = []
    for y in numpy.arange(0, 15, 0.5):
      if not any(x-2 < y and y < x+2 for x in values):
        not_in_ranges.append(y)
    

    You could even use list comprehension again, giving the very pythonic looking:

    not_in_ranges = [y for y in numpy.arange(0, 15, 0.5) if not any(x-2 < y and y < x+2 for x in values)]
    

    Note that the last one is likely the fastest to run since the append call is quite slow and list comprehension is almost always faster. Though it certainly might not be the easiest to understand at a glance if you aren't already used to python list comprehension format.