如何在python中找到范围重叠?

drb*_*sen 32 python range

Python中确定两个范围中哪些值重叠的最佳方法是什么?

例如:

x = range(1,10)
y = range(8,20)

(The answer I am looking for would be the integers 8 and 9.)
Run Code Online (Sandbox Code Playgroud)

给定一个范围,x,迭代另一个范围的最佳方法是什么,y并输出两个范围共享的所有值?在此先感谢您的帮助.

编辑:

作为后续行动,我意识到我还需要知道x是否与y重叠.我正在寻找一种迭代范围列表的方法,并做一些重叠范围的额外事情.是否有一个简单的True/False语句来实现这一目标?

And*_*ark 69

如果步骤始终为+1(这是范围的默认值),则以下应该比将每个列表转换为集合或迭代任一列表更有效:

range(max(x[0], y[0]), min(x[-1], y[-1])+1)
Run Code Online (Sandbox Code Playgroud)

  • 真的,这应该是公认的答案.它是一条线,O(1)交点,而其他的最多是O(n),最坏的是O(n ^ 2). (7认同)
  • 当两个范围之间没有重叠时,此解决方案不会为我们提供正确的输出。 (4认同)
  • 当然可以,如果没有重叠,结果就是预期的空范围。 (4认同)
  • 正如@Pedram提到的,即使没有重叠,这个解决方案也会输出一个范围,该范围将有开始和停止,但该范围实际上是空的。您可以使用 `len(range)` 检查范围是否为空 -> 如果没有重叠,则为 0 (3认同)
  • 为什么不是 `range(max(x.start, y.start), min(x.stop, y.stop))`?需要注意的是,此解决方案仅在“x.step == 1 且 y.step == 1”时才有效。 (2认同)

joa*_*uin 48

尝试使用set intersection:

>>> x = range(1,10)
>>> y = range(8,20)
>>> xs = set(x)
>>> xs.intersection(y)
set([8, 9])
Run Code Online (Sandbox Code Playgroud)

请注意,intersection接受任何iterable作为参数(y不需要将其转换为操作的集合).有一个等效于该intersection方法的运算符:&但是,在这种情况下,它需要两个参数都是集合.

  • @ dr.bunsen这个答案不值得所有这些赞成,也不被接受.1)这个"解决方案"比Andrew的解决方案慢2.5(参见我的回答中的比较)2)结果没有排序,因为它是一个集合; 在某些情况下这可能是一个缺点 (3认同)
  • @eyquem 也许 OP 对简单性(你想要交集?然后你做`交集`)、可读性(这里不需要评论)和这种方法的通用性感到更舒服(它不假设步骤 1 或相同的步骤)范围,您可以将它用于其他可迭代对象,而不仅仅是范围)。速度并不总是更重要的因素(尽管 `itersection` 方法比 plaes `&` 快,并且比列表理解(python 2.6)快得多,这两种方法仍然非常有趣,恕我直言。无论如何,我们正在谈论几种微秒来执行这里的代码)。 (2认同)
  • 感谢您的评论和讨论。我最终选择这个答案是因为可读性以及使用“set()”删除重复项的额外好处。 (2认同)
  • 您不想这样做来查找“range(0, 21984762198598125721534)”和“range(21984762198598125721123, 45823914893546328945328456)”之间的交集。Andrew Clark 回答了一个 O(1) 解决方案,这将是可行的方法。 (2认同)

pla*_*aes 14

您可以使用set s,但要注意set(list)从以下位置删除所有重复的条目list:

>>> x = range(1,10)
>>> y = range(8,20)
>>> list(set(x) & set(y))
[8, 9]
Run Code Online (Sandbox Code Playgroud)


Tim*_*man 10

一种选择是使用列表理解,如:

x = range(1,10) 
y = range(8,20) 

z = [i for i in x if i in y]
print z
Run Code Online (Sandbox Code Playgroud)

  • 据我所知,Python 2.x中的xrange .__ contains__没有这个优化.这是在python 2.7下的sloow:rng = xrange(20,1000000000); 10在rng (2认同)
  • '10 in rng'(False)很慢,在Python 2.7下,'100 in rng'(True)很快; 两者在Python 3.2下都很快. (2认同)

小智 10

如果您寻找两个实值有界区间之间的重叠,那么这非常好:

def overlap(start1, end1, start2, end2):
    """how much does the range (start1, end1) overlap with (start2, end2)"""
    return max(max((end2-start1), 0) - max((end2-end1), 0) - max((start2-start1), 0), 0)
Run Code Online (Sandbox Code Playgroud)

我在网上找不到这个,所以我想出了这个,我在这里发帖。


Rob*_*ugs 8

上面的答案似乎大多过于复杂。这个 liner 在 Python3 中完美运行,将范围作为输入和输出。它还处理非法范围。如果不是 None ,要获取值只需迭代结果。

# return overlap range for two range objects or None if no ovelap
# does not handle step!=1
def range_intersect(r1, r2):
    return range(max(r1.start,r2.start), min(r1.stop,r2.stop)) or None
Run Code Online (Sandbox Code Playgroud)


Pas*_*ten 6

这是 step=1 情况下的简单范围的答案(99% 的时间),当使用集合比较长范围时,它可以比基准快 2500 倍(当您只想知道是否有重叠时) :

x = range(1,10) 
y = range(8,20)

def range_overlapping(x, y):
    if x.start == x.stop or y.start == y.stop:
        return False
    return x.start <= y.stop and y.start <= x.stop

>>> range_overlapping(x, y)
True
Run Code Online (Sandbox Code Playgroud)

要查找重叠值:

def overlap(x, y):
    if not range_overlapping(x, y):
        return set()
    return set(range(max(x.start, y.start), min(x.stop, y.stop)+1))
Run Code Online (Sandbox Code Playgroud)

视觉帮助:

|  |           |    |
  |  |       |    |
Run Code Online (Sandbox Code Playgroud)

基准:

x = range(1,10)
y = range(8,20)

In [151]: %timeit set(x).intersection(y)
2.74 µs ± 11.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [152]: %timeit range_overlapping(x, y)
1.4 µs ± 2.91 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Run Code Online (Sandbox Code Playgroud)

结论:即使对于小范围,它的速度也快两倍。

x = range(1,10000)
y = range(50000, 500000)

In [155]: %timeit set(x).intersection(y)
43.1 ms ± 158 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [156]: %timeit range_overlapping(x, y)
1.75 µs ± 88.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Run Code Online (Sandbox Code Playgroud)

结论:你想在这种情况下使用 range_overlapping 函数,因为它快了 2500 倍(我在加速方面的个人记录)


eyq*_*uem 5

对于“如果x与y重叠或不重叠”:

for a,b,c,d in ((1,10,10,14),
                (1,10,9,14),
                (1,10,4,14),
                (1,10,4,10),
                (1,10,4,9),
                (1,10,4,7),
                (1,10,1,7),
                (1,10,-3,7),
                (1,10,-3,2),
                (1,10,-3,1),
                (1,10,-11,-5)):
    x = range(a,b)
    y = range(c,d)
    print 'x==',x
    print 'y==',y
    b = not ((x[-1]<y[0]) or (y[-1]<x[0]))
    print '    x %s y' % ("does not overlap","   OVERLAPS  ")[b]
    print
Run Code Online (Sandbox Code Playgroud)

结果

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [10, 11, 12, 13]
    x does not overlap y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [9, 10, 11, 12, 13]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [4, 5, 6, 7, 8, 9]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [4, 5, 6, 7, 8]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [4, 5, 6]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [1, 2, 3, 4, 5, 6]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [-3, -2, -1, 0, 1]
    x    OVERLAPS   y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [-3, -2, -1, 0]
    x does not overlap y

x== [1, 2, 3, 4, 5, 6, 7, 8, 9]
y== [-11, -10, -9, -8, -7, -6]
    x does not overlap y
Run Code Online (Sandbox Code Playgroud)

编辑1

速度比较:

from time import clock

x = range(-12,15)
y = range(-5,3)
te = clock()
for i in xrange(100000):
    w = set(x).intersection(y)
print '                     set(x).intersection(y)',clock()-te


te = clock()
for i in xrange(100000):
    w = range(max(x[0], y[0]), min(x[-1], y[-1])+1)
print 'range(max(x[0], y[0]), min(x[-1], y[-1])+1)',clock()-te
Run Code Online (Sandbox Code Playgroud)

结果

                     set(x).intersection(y) 0.951059981087
range(max(x[0], y[0]), min(x[-1], y[-1])+1) 0.377761978129
Run Code Online (Sandbox Code Playgroud)

这些执行时间的比率为2.5