猿问

获取日期时间范围列表的联合和交集python

我有两个datetime范围列表。例如。


l1 = [(datetime.datetime(2018, 8, 29, 1, 0, 0), datetime.datetime(2018, 8, 29, 3, 0, 0)), (datetime.datetime(2018, 8, 29, 6, 0, 0), datetime.datetime(2018, 8, 29, 9, 0, 0))]

l2 = [(datetime.datetime(2018, 8, 29, 2, 0, 0), datetime.datetime(2018, 8, 29, 4, 0, 0)), (datetime.datetime(2018, 8, 29, 5, 0, 0), datetime.datetime(2018, 8, 29, 7, 0, 0))]

我想得到l1and 的并集l2。所需的输出是:


union = [(datetime.datetime(2018, 8, 29, 1, 0, 0), datetime.datetime(2018, 8, 29, 4, 0, 0)), (datetime.datetime(2018, 8, 29, 5, 0, 0), datetime.datetime(2018, 8, 29, 9, 0, 0))]

intersection = [(datetime.datetime(2018, 8, 29, 2, 0, 0), datetime.datetime(2018, 8, 29, 3, 0, 0)), (datetime.datetime(2018, 8, 29, 6, 0, 0), datetime.datetime(2018, 8, 29, 7, 0, 0))]

真实数据可能不会如此完美对齐。


尚方宝剑之说
浏览 432回答 2
2回答

慕田峪7331174

您对日期范围的并集和交集的定义可以简单地描述为:-联盟:In []:from itertools import product[(min(s1, s2), max(e1, e2)) for (s1, e1), (s2, e2) in product(l1, l2) if s1 <= e2 and e1 >= s2]Out[]:[(datetime.datetime(2018, 8, 29, 1, 0), datetime.datetime(2018, 8, 29, 4, 0)),&nbsp;(datetime.datetime(2018, 8, 29, 5, 0), datetime.datetime(2018, 8, 29, 9, 0))]路口:In []:[(max(s1, s2), min(e1, e2)) for (s1, e1), (s2, e2) in product(l1, l2) if s1 <= e2 and e1 >= s2]Out[]:[(datetime.datetime(2018, 8, 29, 2, 0), datetime.datetime(2018, 8, 29, 3, 0)),&nbsp;(datetime.datetime(2018, 8, 29, 6, 0), datetime.datetime(2018, 8, 29, 7, 0))]您可以替换<=和>=使用<以及>他们是否严格有重叠,而不仅仅是碰。

30秒到达战场

因为它可以压缩一组重叠范围:from operator import itemgetterdef consolidate(intervals):&nbsp; &nbsp; sorted_intervals = sorted(intervals, key=itemgetter(0))&nbsp; &nbsp; if not sorted_intervals:&nbsp; # no intervals to merge&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; # low and high represent the bounds of the current run of merges&nbsp; &nbsp; low, high = sorted_intervals[0]&nbsp; &nbsp; for iv in sorted_intervals[1:]:&nbsp; &nbsp; &nbsp; &nbsp; if iv[0] <= high:&nbsp; # new interval overlaps current run&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; high = max(high, iv[1])&nbsp; # merge with the current run&nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; # current run is over&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yield low, high&nbsp; # yield accumulated interval&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; low, high = iv&nbsp; # start new run&nbsp; &nbsp; yield low, high&nbsp; # end the final run联盟l1和l2仅仅是在这两个所有范围的整合l1和l2:def union(l1, l2):&nbsp; &nbsp; return consolidate([*l1, *l2])AChampion 的代码充分完成了l1和 的交集l2(如果 中的任何范围l1和 中的任何范围之间存在任何重叠l2,则该重叠应该出现在结果中),但它可能导致范围碎片化;我们可以使用相同的函数来连接相邻或重叠的范围:from itertools import productdef intersection(l1, l2):&nbsp; &nbsp; result = ((max(s1, s2), min(e1, e2)) for (s1, e1), (s2, e2) in product(l1, l2) if s1 < e2 and e1 > s2)&nbsp; &nbsp; return consolidate(result)一个例子:l1 = [(1, 7), (4, 8), (10, 15), (20, 30), (50, 60)]l2 = [(3, 6), (8, 11), (15, 20)]print(list(union(l1, l2)))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# [(1, 30), (50, 60)]print(list(intersection(l1, l2)))&nbsp; # [(3, 6), (10, 11)](为了清楚起见,该示例使用整数,但它适用于任何可比较的类型。具体来说,对于 OPl1和l2,代码产生 OP 所需的datetime结果。)
随时随地看视频慕课网APP

相关分类

Python
我要回答