python 中的“合并”时间范围

Nei*_*urn 2 python datetime

我有很多时间打开/关闭“规则”,我希望将它们合并以获得当天的一组统一规则。

from datetime import time

times = [
    {"time_open": time(9, 0), "time_close": time(11, 0)},
    {"time_open": time(9, 0), "time_close": time(12, 0)},
    {"time_open": time(13, 0), "time_close": time(18, 0)},
    {"time_open": time(15, 0), "time_close": time(19, 0)},
]

# something would produce

merged_times = [
    {"time_open": time(9, 0), "time_close": time(12, 0)},
    {"time_open": time(13, 0), "time_close": time(19, 0)},
]
Run Code Online (Sandbox Code Playgroud)

我脑子里有几种方法 - 但速度可能是所选方法的主要驱动因素。

Mar*_*ers 6

您需要从一组排序的间隔开始;如果它们尚未排序,请从以下开始:

from operator import itemgetter

sorted_times = sorted(times, key=itemgetter('time_open', 'time_close'))
Run Code Online (Sandbox Code Playgroud)

然后,您可以简单地通过将开始时间与之前的结束时间进行比较来合并时间;当它们不重叠时产生更新时间:

def merge_times(times):
    times = iter(times)
    merged = next(times).copy()
    for entry in times:
        start, end = entry['time_open'], entry['time_close']
        if start <= merged['time_close']:
            # overlapping, merge
            merged['time_close'] = max(merged['time_close'], end)
        else:
            # distinct; yield merged and start a new copy
            yield merged
            merged = entry.copy()
    yield merged
Run Code Online (Sandbox Code Playgroud)

这是一个生成器函数,因此合并时间是根据需要生成的。使用循环来一一处理这些,或者使用list()生成器将所有结果拉入列表对象。

使用示例数据进行演示(恰好已经排序):

>>> for entry in merge_times(times):
...     print(entry)
...
{'time_open': datetime.time(9, 0), 'time_close': datetime.time(12, 0)}
{'time_open': datetime.time(13, 0), 'time_close': datetime.time(19, 0)}
>>> list(merge_times(times))
[{'time_open': datetime.time(9, 0), 'time_close': datetime.time(12, 0)}, {'time_open': datetime.time(13, 0), 'time_close': datetime.time(19, 0)}]
Run Code Online (Sandbox Code Playgroud)