2010-09-15 7 views
11

Als allgemeine Frage frage ich mich, ob es eine elegantere/effizientere Möglichkeit gibt, dies zu tun. Ich habe eine Funktion, die zwei Anfangs-/Endtupel von Daten vergleicht, die wahr zurückgeben, wenn sie sich schneiden.python date interval intersection

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 

so, wenn:

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

dann:

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

usw.

Ich bin neugierig zu wissen, ob es eine weitere pythonic/elegant/effizienter/weniger ausführlich/allgemein besser, Möglichkeit, dies mit vielleicht mxDateTime oder einem cleveren Hack mit timedelta oder set() zu tun?

Eine alternative und nützliche Form wäre für die Funktion eines Start/Ende Tupel der Kreuzung zurück, wenn ein

Dank

+0

Sie sollten Timedeltas verwenden, um die Dauer von 't1 ⇔ t2' darzustellen und ich denke an das nächste Bit. http://docs.python.org/library/datetime.html#datetime.timedelta – msw

Antwort

19

Es ist nicht wirklich mehr Pythonic, aber Sie können einfach die Logik auf einer Kreuzung etwas entscheiden. Diese besondere Probleme erntet viel up:

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

Um zu sehen, warum das funktioniert, denken über die verschiedenen Möglichkeiten, die die beiden Intervalle schneiden und sehen kann, dass der Ausgangspunkt eines immer im Bereich des anderen sein muss.

+0

ja! Sehr schön. Es lässt mich immer noch ein wenig schielen, aber Sie haben meine erschöpfende Analyse in einen sehr sauberen Ausdruck gebracht. Vielen Dank, das hilft mein Denken zu klären. – jjon

+0

Laut meinem Komponententest funktioniert es nicht, wenn das Ende von 't1' der Anfang von 't2' ist. –

+0

Wenn t2start <= t1end? Ich denke, du solltest deinen Komponententest noch einmal überprüfen. – Amoss

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

Will nicht, dass deckt alle schneidenden Sätze zu finden ist?

+0

Nun, Ihr Code vereinfacht die Rückgabe t1end> = t2start und t1start <= t2end – Amoss

+0

ah, rechts ... 1 mehr – nmichaels

6

Hier ist eine Version, die Ihnen den Bereich der Kreuzung geben. IMHO, es ist vielleicht nicht die optimale Bedingungen, aber es zeigt deutlich, wenn t2 mit t1 überschneidet. Sie können basierend auf anderen Antworten ändern, wenn Sie nur das Wahr/Falsch wollen.

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 
+1

FYI ... Verkettung Vergleichsoperatoren: http://StackOverflow.com/Questions/101268/Hidden-Features-of-Python/101945#101945 – fseto

+0

Vielen Dank für den Link zu Verkettung Operatoren, das ist sehr hilfreich. – jjon

+0

Dies kann an den Enddaten mit min beschönigt werden. z.B. wenn start1 <= start2 <= end1: return (start2, min (end1, end2)) – JeremyKun

7

Eine alternative und hoffentlich verständliche Lösung:

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: 

Wir leicht das Intervall der Überlappung bekommen, ist es (latest_start, earliest_end). Beachten Sie, dass "next_start" gleich "first_end" sein kann.

Es sollte beachtet werden, dass dies davon ausgeht, dass A_start <= A_end und B_start <= B_end.

+2

Dieser ist am besten lesbar. Sie können auch ganz einfach zurückkehren (frühestes_end-aktuelles_Start), um eine Messung der Gesamtüberlappungsmenge zu erhalten. – cxrodgers

2
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 

Nur die Start < = other_finish und other_start < = Finish Notwendigkeit wahr zu sein, um eine Überlappung zurückzukehren.

+0

Eine gute Antwort würde eine Erklärung enthalten, warum dies alles lösen würde. – Qirel