【问题标题】:Checking two time intervals are overlapping or not检查两个时间间隔是否重叠
【发布时间】:2016-02-26 05:39:45
【问题描述】:

我有这种两种不同的间隔集:

Intervals1:
{'ending_time': '2016-02-26 07:10:40.276504', 'starting_time': '2016-02-26 07:10:39.286168'}
{'ending_time': '2016-02-26 07:10:40.722193', 'starting_time': '2016-02-26 07:10:40.301116'}
{'ending_time': '2016-02-26 07:10:41.329731', 'starting_time': '2016-02-26 07:10:40.812676'}
{'ending_time': '2016-02-26 07:10:42.146669', 'starting_time': '2016-02-26 07:10:41.419473'}
{'ending_time': '2016-02-26 07:10:42.413005', 'starting_time': '2016-02-26 07:10:42.203540'}
{'ending_time': '2016-02-26 07:10:42.686456', 'starting_time': '2016-02-26 07:10:42.442964'}
{'ending_time': '2016-02-26 07:10:43.198191', 'starting_time': '2016-02-26 07:10:42.746994'}
{'ending_time': '2016-02-26 07:10:44.502593', 'starting_time': '2016-02-26 07:10:43.288611'}
{'ending_time': '2016-02-26 07:10:46.525823', 'starting_time': '2016-02-26 07:10:44.709627'}
{'ending_time': '2016-02-26 07:10:47.098280', 'starting_time': '2016-02-26 07:10:46.886541'}
--------------------------
Interval2:
{'ending_time': '2016-02-26 07:10:41.482954', 'starting_time': '2016-02-26 07:10:39.590220'}
{'ending_time': '2016-02-26 07:10:42.615738', 'starting_time': '2016-02-26 07:10:41.649375'}
{'ending_time': '2016-02-26 07:10:46.365902', 'starting_time': '2016-02-26 07:10:45.987907'}
{'ending_time': '2016-02-26 07:10:47.698375', 'starting_time': '2016-02-26 07:10:46.510641'}

我正在使用这一行将这些日期时间字符串转换为真实的日期时间对象:

datetime.datetime.strptime(dictionary['starting_time'], "%Y-%m-%d %H:%M:%S.%f")

我在这里尝试做的是通过比较这两个不同的集合来匹配重叠的时间间隔。

例如; Intervals1[0] 和 Intervals2[0] 重叠 但 Intervals1[7] 和 Intervals2[0] 不重叠。

那么正确的方法是什么?对我来说,一个简短的解释就足够了。

【问题讨论】:

标签: python python-2.7 datetime time compare


【解决方案1】:

datetime对象支持比较,所以你只需要检查第一个开始时间是否在另一个的开始和结束之间,或者第一个结束时间是否在另一个的开始停止之间,反之亦然。

def overlap(first_inter,second_inter):
    for f,s in ((first_inter,second_inter), (second_inter,first_inter)):
        #will check both ways
        for time in (f["starting_time"], f["ending_time"]):
            if s["starting_time"] < time < s["ending_time"]:
                return True
    else:
        return False

编辑:还请注意,由于日期字符串的格式首先具有最重要的值,因此可以轻松进行比较,而无需将它们转换为 datetime 对象。

Edit2:这是一个将所有组合及其结果记录到字典中的方法:

import itertools

combos = {(i1,i2):overlap(int1,int2)
             for (i1,int1),(i2,int2)
                in itertools.product(enumerate(Intervals1),enumerate(Intervals2))}

print(*combos.items(),sep="\n")

这样combos[0,1]就会枯萎Intervals[0]Intervals[1]重叠等等。

然后只获得一组可以使用的重叠时间:

overlapped = set(com for com,was_overlapped in combos.items() if was_overlapped)

最后编辑:我很抱歉使用很长的dict comprehension,很难处理格式混乱的数据,如果原始时间列表有一个模式,那么只需使用 dict 理解的 for 循环部分会产生预期的结果:

for (i1,int1),(i2,int2) in itertools.product(enumerate(Intervals1),enumerate(Intervals2)):
    if overlap(int1,int2):
        print(i1,i2)

或对overlapped 集进行排序,您可以使用sorted 内置函数:

overlapped = sorted(overlapped) #this gives a list

【讨论】:

  • Thx,它适用于一一比较,但如果它返回 False,我需要检查更多组合。例如,Intervals1[0] 和 Intervals2[0] 不重叠,但 Invervals1[0] 和 Intervals2[1] 可能重叠。那么如何以最小的时间复杂度比较整个列表呢?
  • 顺便说一下,这些 Intervals1 和 Intervals2 列表本身就有时间顺序。
  • 我没有注意到列表本身的顺序,在这种情况下,可能有比我刚刚添加的方法更快的方法,但它能够在 6.9 中使用 timeit.timeit 进行 10000 次运行秒,所以可能就足够了
  • 我怎样才能从组合中只获得真正的组合以及timeit.timeit 是什么?你能解释一下吗:)
  • 添加了仅获取​​ True 集的编辑,但对于 timeit,您应该转到 google.com/#q=python+timeitdocs.python.org/2/library/timeit.html#timeit.timeit,我的代码是 def test():combos = &lt;code in answer&gt;; print(timeit.timeit(test,number=100000))
【解决方案2】:

您可以像这样比较范围:

timerange1 = {'ending_time': '2016-02-26 07:10:40.276504', 'starting_time': '2016-02-26 07:10:39.286168'}
timerange2 = {'ending_time': '2016-02-26 07:10:41.482954', 'starting_time': '2016-02-26 07:10:39.590220'}

# use a function to make this 'interval' data structure (instead of me being lazy)
interval1 = [datetime.datetime.strptime(timerange1['starting_time'], "%Y-%m-%d %H:%M:%S.%f")]
             datetime.datetime.strptime(timerange1['ending_time'], "%Y-%m-%d %H:%M:%S.%f")]
interval2 = [datetime.datetime.strptime(timerange2['starting_time'], "%Y-%m-%d %H:%M:%S.%f")]
             datetime.datetime.strptime(timerange2['ending_time'], "%Y-%m-%d %H:%M:%S.%f")]

def overlaps(interval1, interval2):
    results = []
    for timestamp in interval1:
        results.append(interval2[0] < timestamp < interval2[1])
    for timestamp in interval2:
        results.append(interval1[0] < timestamp < interval1[1])
    return True in results

【讨论】:

  • 您使用列表中间步骤是否有原因?
  • 完整检查是否有任何时间戳落在任何间隔之间。间隔 1 的开始/结束时间可能不在间隔 2 之间,但间隔 1“更宽”,因此间隔 2 的开始/结束时间可能落在间隔 1 之间。有意义吗?
  • 不,我会编辑你的帖子,展示我会怎么做,你不必接受。
  • 酷,我将在我的答案中添加更多上下文来解释我为什么使用该列表。
  • 哦!我以为您的意思是“重叠”功能上的“结果”列表,而不是我将提问者词典转换为列表。我只是在本地机器上运行它时这样做,以使复制/粘贴更容易。对此感到抱歉。
【解决方案3】:

对于 Intervals1 中的 m 条记录和 Intervals2 中的 n 条记录,下面只需要 200 万次比较,而不是 400 万次。

Intervals1 = [
    {'ending_time': '2016-02-26 07:10:40.276504', 'starting_time': '2016-02-26 07:10:39.286168'},
    {'ending_time': '2016-02-26 07:10:40.722193', 'starting_time': '2016-02-26 07:10:40.301116'},
    {'ending_time': '2016-02-26 07:10:41.329731', 'starting_time': '2016-02-26 07:10:40.812676'},
    {'ending_time': '2016-02-26 07:10:42.146669', 'starting_time': '2016-02-26 07:10:41.419473'},
    {'ending_time': '2016-02-26 07:10:42.413005', 'starting_time': '2016-02-26 07:10:42.203540'},
    {'ending_time': '2016-02-26 07:10:42.686456', 'starting_time': '2016-02-26 07:10:42.442964'},
    {'ending_time': '2016-02-26 07:10:43.198191', 'starting_time': '2016-02-26 07:10:42.746994'},
    {'ending_time': '2016-02-26 07:10:44.502593', 'starting_time': '2016-02-26 07:10:43.288611'},
    {'ending_time': '2016-02-26 07:10:46.525823', 'starting_time': '2016-02-26 07:10:44.709627'},
    {'ending_time': '2016-02-26 07:10:47.098280', 'starting_time': '2016-02-26 07:10:46.886541'}
    ]
Intervals2 = [
    {'ending_time': '2016-02-26 07:10:41.482954', 'starting_time': '2016-02-26 07:10:39.590220'},
    {'ending_time': '2016-02-26 07:10:42.615738', 'starting_time': '2016-02-26 07:10:41.649375'},
    {'ending_time': '2016-02-26 07:10:46.365902', 'starting_time': '2016-02-26 07:10:45.987907'},
    {'ending_time': '2016-02-26 07:10:47.698375', 'starting_time': '2016-02-26 07:10:46.510641'}
    ]

for i1, d1 in enumerate(Intervals1):
  for i2, d2 in enumerate(Intervals2):
    start1 = d1["starting_time"]
    start2 = d2["starting_time"]
    end1 = d1["ending_time"]
    end2 = d2["ending_time"]

    if end1 >= start2 and end2 >= start1:
        print("Intervals1", i1, "overlaps with Intervals2", i2)

【讨论】:

    【解决方案4】:

    又好又短。 从同事那里拿的,不知道作者)))

    def is_overlapped(ranges):
        sorted_ranges = sorted(ranges, key=lambda begin_end: begin_end[0])
        return list(chain(*sorted_ranges)) != sorted(chain(*sorted_ranges))
    

    ############################################## ###################

    不重叠:

    打印(is_overlapped([ (日期时间(2023, 10, 1), 日期时间(2023, 12, 31)), (日期时间(2020, 11, 1), 日期时间(2020, 12, 2)) ]))

    False
    

    第一秒:

    print(is_overlapped([ (datetime(2013, 10, 1), datetime(2013, 12, 31)), (日期时间(2000, 11, 1), 日期时间(2020, 12, 2)) ]))

    True
    

    第二名:

    print(is_overlapped([ (datetime(2013, 10, 1), datetime(2023, 12, 31)), (日期时间(2020, 11, 1), 日期时间(2020, 12, 2)) ]))

    True
    

    第一个变成第二个:

    print(is_overlapped([ (datetime(2010, 10, 1), datetime(2013, 12, 31))), (日期时间(2013, 11, 1), 日期时间(2015, 12, 2)) ]))

    True
    

    第二变第一:

    print(is_overlapped([ (datetime(2011, 10, 1), datetime(2013, 12, 31)), (日期时间(2010, 11, 1), 日期时间(2011, 12, 2)) ]))

    True
    

    【讨论】:

      猜你喜欢
      • 2016-06-02
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      • 2013-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多