【问题标题】:python date interval intersectionpython日期间隔交集
【发布时间】:2010-09-15 19:47:28
【问题描述】:

作为一个普遍感兴趣的问题,我想知道是否有更优雅/更有效的方法来做到这一点。我有一个函数可以比较两个日期的开始/结束元组,如果它们相交则返回 true。

from datetime import date
def date_intersection(t1, t2):
    t1start, t1end = t1[0], t1[1]
    t2start, t2end = t2[0], t2[1]

    if t1end < t2start: return False
    if t1end == t2start: return True
    if t1start == t2start: return True
    if t1start < t2start and t2start < t1end: return True
    if t1start > t2start and t1end < t2end: return True
    if t1start < t2start and t1end > t2end: return True
    if t1start < t2end and t1end > t2end: return True
    if t1start > t2start and t1start < t2end: return True
    if t1start == t2end: return True
    if t1end == t2end: return True 
    if t1start > t2end: return False

如果:

d1 = date(2000, 1, 10)
d2 = date(2000, 1, 11)
d3 = date(2000, 1, 12)
d4 = date(2000, 1, 13)

然后:

>>> date_intersection((d1,d2),(d3,d4))
False
>>> date_intersection((d1,d2),(d2,d3))
True
>>> date_intersection((d1,d3),(d2,d4))
True

等等

我很想知道是否有更 Pythonic/优雅/更高效/更少冗长/通常更好的方法来做到这一点,可能是 mxDateTime 或一些聪明的 hack 使用 timedelta 或 set()?

另一种有用的形式是函数返回交集的开始/结束元组(如果找到)

谢谢

【问题讨论】:

标签: python datetime intersection


【解决方案1】:

这并不是真正的 Pythonic,但您可以通过简单的逻辑来决定交叉点。这个特殊的问题经常出现:

return (t1start <= t2start <= t1end) or (t2start <= t1start <= t2end)

要了解为什么会这样,请考虑两个区间可以相交的不同可能方式,并看到一个区间的起点必须始终在另一个区间的范围内。

【讨论】:

  • 是的!非常好。它仍然让我有点眼花缭乱,但你已经将我详尽的案例分析折叠成一个非常干净的表达方式。非常感谢,这有助于澄清我的想法。
  • 根据我的单元测试,如果t1 的结尾是t2 的开头,则它不起作用。
  • 当 t2start
【解决方案2】:

另一种可能更容易理解的解决方案:

def has_overlap(a_start, a_end, b_start, b_end):
    latest_start = max(a_start, b_start)
    earliest_end = min(a_end, b_end)
    return latest_start <= earliest_end

我们可以很容易地得到重叠的间隔,它是(latest_start, earliest_end)。请注意,latest_start 可以等于 early_end。

需要注意的是,这里假设a_start &lt;= a_endb_start &lt;= b_end

【讨论】:

  • 这个可读性最强。此外,您可以轻松返回 (earliest_end-latest_start) 以测量重叠总量。
  • 这是最好的答案!
【解决方案3】:

这是一个为您提供相交范围的版本。恕我直言,它可能不是最优化的条件,但它清楚地显示了 t2 何时与 t1 重叠。如果您只想要真/假,您可以根据其他答案进行修改。

if (t1start <= t2start <= t2end <= t1end):
    return t2start,t2end
elif (t1start <= t2start <= t1end):
    return t2start,t1end
elif (t1start <= t2end <= t1end):
    return t1start,t2end
elif (t2start <= t1start <= t1end <= t2end):
    return t1start,t1end
else:
    return None

【讨论】:

【解决方案4】:
intersection_length = min(t1end, t2end) - max(t1start, t2start)
return intersection_length >= 0 

这将接受由单个点组成的交集;否则使用&gt; 0

直觉是相交区间,如果存在的话,从最高起点开始,在最低终点结束。有两种可能:

  1. 这是一个正确的区间,长度可能为零。

  2. 起点和终点最终被交换。这意味着两个区间之间存在间隙,您可以将其称为“负相交”。

【讨论】:

    【解决方案5】:
    Final Comparison: start <= other_finish and other_start <= finish
    
    # All of the conditions below result in overlap I have left out the non overlaps
    
    start <= other_start | start <= other_finish | other_start <= finish | finish <= other_finish 
    
          0                        1                        1                        0                   
          0                        1                        1                        1
          1                        1                        1                        0          
          1                        1                        1                        1
    

    只有 start 和 other_start 需要为 true 才能返回重叠。

    【讨论】:

    • 一个好的答案将包括一些解释为什么这会解决任何问题。
    【解决方案6】:
    if t1end < t2start or t1start > t2end: return False
    if t1start <= t2end or t2start <= t1start: return True
    return False
    

    这不会涵盖所有相交集吗?

    【讨论】:

    • 好吧,您的代码简化为返回 t1end >= t2start 和 t1start
    【解决方案7】:

    答案很晚,但在我看来,最简单、最不让人头疼的解决方案是:

    def date_intersection(t1, t2):
        t1, t2 = sorted([t1, t2], key=lambda t: t[0])
        t1end = t1[1]
        t2start = t2[0]
        return t1 end <= t2start
    

    我可能还会考虑将“时间间隔”的概念表达为一个类,所以我可以做更多类似的事情:

    def date_intersection(interval1, interval2):
        i1, i2 = sorted([interval1, interval2], key=lambda i: i.start)
        return i1.end <= i2.start
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-04
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多