如何验证时间窗口之间是否存在重叠

时间:2019-04-08 17:08:11

标签: python datetime

系统会为您提供配对列表。每对存储代表一个时间窗口的开始和结束日期。任务是验证是否存在任何重叠。

请注意,可以使用两个嵌套的for循环遍历periods和一些if条件来验证是否不存在重叠,从而轻松解决该问题。但是,我很想看看是否有一个更具可读性和优雅的解决方案,该解决方案可以使循环保持不变,并且if语句的数量最少,并且不一定使用标准库。

相邻条目之间不一定发生重叠。

列表periods的时间窗口少于10个。我不关心CPU时间。我担心代码的可读性。

from datetime import datetime

overlapping_periods = [
    [datetime(2019, 1, 1), datetime(2019, 1, 5)],
    [datetime(2019, 1, 6), datetime(2019, 1, 10)],
    [datetime(2019, 1, 9), datetime(2019, 1, 15)],
]
non_overlapping_periods = [
    [datetime(2019, 1, 1), datetime(2019, 1, 5)],
    [datetime(2019, 1, 6), datetime(2019, 1, 10)],
    [datetime(2019, 1, 11), datetime(2019, 1, 15)],
]

# Find an elegant `verify_overlaps`.
verify_overlaps(overlapping_periods)  # True
verify_overlaps(non_overlapping_periods)  # False

3 个答案:

答案 0 :(得分:0)

是这么简单,还是我错过了什么?

def verify_overlaps(s):
    s = sorted(s) # sorts on first member of each element by default
    current = datetime.min
    for dt0, dt1 in s:
        if dt0 <= current:
            return False
        current = dt1
    return True

您没有指定一个周期的开始与另一个周期的结束是否被视为重叠。只需“ <” vs“ <=”。

答案 1 :(得分:0)

您可以使用sorted函数,该函数返回一个可迭代的对象(默认情况下,它将按列表中的第一个参数排序):

def verify_overlap(periods):
    d2_previous = datetime(1900,1,1)
    for d1, d2 in (sorted(periods)):
        if d1 <= d2_previous:
            return False
        d2_previous = d2
    return True

答案 2 :(得分:0)

我不知道您是否认为这更具可读性,但是:

import itertools
from typing import NamedTuple


class Period(NamedTuple):
    start: datetime
    end: datetime

    def __and__(self, other):
        return (
            other.start in self or
            self.start in other
        )

    def __contains__(self, dt):
        return dt >= self.start and dt < self.end


def pairwise(iterable):
    a, b = itertools.tee(iterable)
    next(b, None)
    return zip(a, b)


def verify_overlaps(periods):
    return any(a & b for a, b in pairwise(sorted(periods)))