为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

尚方宝剑之说 2021-06-04 09:37:24
我有两个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))]真实数据可能不会如此完美对齐。
查看完整描述

2 回答

?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

您对日期范围的并集和交集的定义可以简单地描述为:-


联盟:


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

 (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)),

 (datetime.datetime(2018, 8, 29, 6, 0), datetime.datetime(2018, 8, 29, 7, 0))]

您可以替换<=和>=使用<以及>他们是否严格有重叠,而不仅仅是碰。


查看完整回答
反对 回复 2021-06-06
?
30秒到达战场

TA贡献1828条经验 获得超6个赞

因为它可以压缩一组重叠范围:


from operator import itemgetter


def consolidate(intervals):

    sorted_intervals = sorted(intervals, key=itemgetter(0))


    if not sorted_intervals:  # no intervals to merge

        return


    # low and high represent the bounds of the current run of merges

    low, high = sorted_intervals[0]


    for iv in sorted_intervals[1:]:

        if iv[0] <= high:  # new interval overlaps current run

            high = max(high, iv[1])  # merge with the current run

        else:  # current run is over

            yield low, high  # yield accumulated interval

            low, high = iv  # start new run


    yield low, high  # end the final run

联盟l1和l2仅仅是在这两个所有范围的整合l1和l2:


def union(l1, l2):

    return consolidate([*l1, *l2])

AChampion 的代码充分完成了l1和 的交集l2(如果 中的任何范围l1和 中的任何范围之间存在任何重叠l2,则该重叠应该出现在结果中),但它可能导致范围碎片化;我们可以使用相同的函数来连接相邻或重叠的范围:


from itertools import product


def intersection(l1, l2):

    result = ((max(s1, s2), min(e1, e2)) for (s1, e1), (s2, e2) in product(l1, l2) if s1 < e2 and e1 > s2)

    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)))         # [(1, 30), (50, 60)]

print(list(intersection(l1, l2)))  # [(3, 6), (10, 11)]

(为了清楚起见,该示例使用整数,但它适用于任何可比较的类型。具体来说,对于 OPl1和l2,代码产生 OP 所需的datetime结果。)


查看完整回答
反对 回复 2021-06-06
  • 2 回答
  • 0 关注
  • 431 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信