遍历范围和 return 不在任何范围内的范围?

Iterate through ranges and return those not in any range?

我有一个花车列表。

values = [2.3, 6.4, 11.3]

我想要做的是从大小为 delta = 2 的列表中的每个值中找到一个范围,然后遍历另一个浮点数范围并将每个浮点数与每个范围进行比较,然后 return不在任何范围内的浮点数。

我目前的情况是,

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)

但很明显,由于以下几个原因,这不起作用:冗余、没有一次检查所有范围等。我是编码新手,我正在努力抽象地思考以解决这个问题。如果能帮助制定行动计划,我们将不胜感激。

编辑 为清楚起见,我想要的是每个值的范围列表(或者可能是一个 numpy 数组?)as

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

以及 return 从 0 到 15 的任何浮点数,增量为 0.5,但不属于任何这些范围,因此最终输出将是:

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

我已经做了对比分析(在jupyter notebook中)。看看结果。

# First cell
import numpy as np
values = np.random.randn(1000000)
values.shape

# Second cell
%%time
not_in_range =[]
for x in values:
        pre = float(x - 2)
        post = float(x + 2)
        for y in np.arange(0,15,0.5):
                if (pre <= y <= post) == True:
                        pass
                else:
                        not_in_range.append(y)
# Second cell output - Wall time: 37.2 s

# Third cell
%%time
pre = values - 2
post = values + 2

whole_range = np.arange(0,15,0.5)
whole_range

search_range = []
for pr, po in zip(pre, post):
    pr = (int(pr) + 0.5) if (pr%5) else int(pr) 
    po = (int(po) + 0.5) if (po%5) else int(po) 
    search_range += list(np.arange(pr, po, 0.5))
    
whole_range = set(whole_range)
search_range = set(search_range)
print(whole_range.difference(search_range))

# Third cell output - Wall time: 3.99 s

要生成范围列表,您可以快速理解列表:

ranges = [[x-2, x+2] for x in values]

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

然后,到return不属于任何范围的从0到15(以0.5为增量)的任何浮点数,您可以使用:

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]

解释: 这遍历每个可能的值,如果它不在任何区间内,则将其附加到 not_in_ranges 列表。为了检查它是否在区间内,我使用内置 python 函数 any 检查列表 ranges 中是否有任何前值和 post 值 return 当 pre < y < post 时为真(即如果 y 在任何间隔中)。如果这是 False,则它不适合 任何 间隔,因此被添加到此类值的列表中。


或者,如果您只需要结果(而不是两个列表),您可以将两者结合起来:

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)

您甚至可以再次使用列表理解,给出非常 pythonic 的外观:

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)]

请注意,最后一个可能是最快的 运行,因为追加调用非常慢,而列表理解几乎总是更快。如果您还没有习惯 python 列表理解格式,那么它肯定不是最容易一目了然的。

可以使用区间库intvalpy

from intvalpy import Interval
import numpy as np

values = [2.3, 6.4, 11.3]
delta = 2
intervals = values + Interval(-delta, delta)

not_in_ranges = []
for k in np.arange(0, 15, 0.5):
    if not k in intervals:
        not_in_ranges.append(k)
print(not_in_ranges)

区间是根据区间算术运算的构造定义创建的。 in 运算符检查一个点(或一个区间)是否包含在另一个区间内。