如何在Python 3.x中检查一个范围是否是另一个范围的一部分

16

如何简单检查一个区间是否是另一个区间的子区间?

range1 in range2 的效果并不符合预期。

4个回答

21
你可以通过以下方式在O(1)时间内完成操作:
def range_subset(range1, range2):
    """Whether range1 is a subset of range2."""
    if not range1:
        return True  # empty range is subset of anything
    if not range2:
        return False  # non-empty range can't be subset of empty range
    if len(range1) > 1 and range1.step % range2.step:
        return False  # must have a single value or integer multiple step
    return range1.start in range2 and range1[-1] in range2

使用中:

>>> range_subset(range(0, 1), range(0, 4))
True

1
@ÁlvaroH.G 在评论中编写的代码并不易读,为什么不发表一个新的答案呢?请注意,您还可以编写一个名为 range_overlap 的新函数,它只需返回 range_subset(r1, r2) or range_subset(r2, r1),这样做的好处是采用了惰性求值(如果 r1r2 的子集,则无需检查 r2 是否是 r1 的子集)。 - jonrsharpe

4
< p > set((range(0,1))).issubset(range(0,4)) 可以完成它。


4
这个方法可以工作,但对于大范围的数据可能效率低下。例如,一个包含一百万个整数的范围将需要构建一个包含一百万个项目的集合。 - Kevin

4

我曾经遇到过类似的问题:如何判断两个范围是否重叠。因此,函数中引入范围的顺序对我来说是一个限制(顺序不应该影响结果)。这是我提出的解决方案(受@jonrsharpe答案的启发):

def range_overlap(range1, range2):
  """Whether range1 and range2 overlap."""
  x1, x2 = range1.start, range1.stop
  y1, y2 = range2.start, range2.stop
  return x1 <= y2 and y1 <= x2

a = range(20, 25, 2)
b = range(23, 25, 3) # different step does not matter
print(list(a), list(b)) # [20, 22, 24] [23]
range_overlap(a, b) # True

如果任何一个范围为空:

# if range1 is non-empty and range2 is empty
a = range(20, 25, 1)
b = range(22, 22, 3) # empty but the range start and end overlap

assert range_overlap(a, b) == range_overlap(a, b)
range_overlap(a, b)
# True

3

在我看来,这是最易读的方法,但效率较低:

all(e in range2 for e in range1)

如果两个范围的步长相同,我认为这将是最有效的:

range1[0] in range2 and range1[-1] in range2

第一个看起来没问题,但是如果范围的步长不是1,则第二个可能会失败。例如 range(0,9,3)range(0,8,2) - Kevin
1
高效的版本在range1的步长与range2不互质的情况下可能会出现问题。考虑range(0,15,5)和range(0,12,2)。 - J Richard Snape
另外补充一点 - 如果range2中的步长大于range1中的步长,无论是否互质。 - J Richard Snape
两者对 xrange 同样适用,而 xrange 不提供 .step(或任何)方法。变量 any(...) 可用于检查交集而不是子集。而在使用 range 时谈论大型集合的效率只是愚蠢的。 - Orwellophile
注意输入如 range(1, 1) -> range(2, 4)。根据您比较的范围,这可能会变成 all([]) -> Trueall(e in range(2, 4) for e in range(1, 1)) 的计算结果为 True - Josmoor98

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接