没有集合!
我无法使用集合,因为:
- 范围将太长。
- 它们会占用太多内存
- 集本身的创建将花费太长时间。
如果只使用范围的端点,是否有最佳方法来减去两个范围列表?
示例:
r1 = (1, 1000), (1100, 1200)
r2 = (30, 50), (60, 200), (1150, 1300)
r1 - r2 = (1, 29), (51, 59), (201, 1000), (1100, 1149)
字符串
其他信息:
- r2不必与r1重叠
- r1和r2不会有重叠的配对。例如,r1不会同时有(0,30)和(10,25)
谢谢.
9条答案
按热度按时间relj7zay1#
interval包可以提供您所需要的一切。
字符串
k7fdbhmy2#
这是一个有趣的问题!
我认为这是正确的,而且它相当紧凑。它应该适用于所有类型的重叠范围,但它假设格式良好的范围(即
[x, y)
,其中x < y
)。为了简单起见,它使用[x, y)
样式的范围。它基于实际上只有六种可能的排列(结果在()中)的观察:编辑:我找到了一个更紧凑的表示:
字符串
给定一个排序的端点列表,如果
endpoints[0] == s1
,那么前两个端点应该在结果中。如果endpoints[3] == e1
,那么最后两个端点应该在结果中。如果都没有,那么应该没有结果。“我还没怎么测试过,完全有可能出错,如果发现错误请告诉我!”
型
测试:
型
nkkqxpd93#
一个解决方案(除了这里介绍的所有其他不同的解决方案之外)是使用区间/段树(它们实际上是一样的):
http://en.wikipedia.org/wiki/Segment_tree
http://en.wikipedia.org/wiki/Interval_tree的
这样做的一个很大的好处是,它是微不足道的做任意布尔运算(不仅仅是减法)使用同一段代码。在de贝格中有对这种数据结构的标准处理。要对一对区间树执行任何布尔运算,(包括减法)你只要把它们合并在一起。这里有一些(诚然幼稚)Python代码,用于对不平衡的范围树执行此操作。它们不平衡的事实对合并树所需的时间没有影响,然而,这里的树构造是真正愚蠢的部分,最终是二次的(除非reduce是通过分区执行的,我有点怀疑)。无论如何,你去了:
字符串
我写得很快,没有测试太多,所以可能会有bug。(你只需在merge中将它们作为参数传递给op)。(这也是结果中的间隔数)。作为一个例子,我在你提供的案例上运行了它:
型
我得到了以下输出:
[(1,29),(51,59),(201,1000),(1100,1149)]
这似乎与你所期望的一致。现在,如果你想做一些其他的布尔运算,这里是它如何使用相同的函数工作:
型
rryofs0p4#
我想我误解了这个问题,但如果
r2
是r1
的子集,则此代码有效字符串
然后,你做:
更新:注意
r2
的最后一个间隔与我的意思不同。型
wpcxdonn5#
这里有一个快速的python函数,它可以做减法,不管初始列表是否格式良好(即在做减法之前,将列表转换为最小的等效范围列表,排序):
字符串
vcirk6k66#
有趣的问题!另一个实现,虽然你已经有很多了。这很有趣!包括一些额外的“装饰”,使我正在做的更明确。
字符串
我得到正确的输出:
型
hmmo2u0o7#
而不是https://pypi.org/project/interval/1.0.0/使用https://pypi.org/project/python-ranges/
字符串
nr9pn0ug8#
这是相当丑陋的,但它确实适用于给定的示例
字符串
打印:
型
gz5pxeao9#
另一个选择是使用portion,它支持python3
字符串