2012-01-28 12 views
47

मेरे पास दो दिनांक सीमाएं हैं जहां प्रत्येक श्रेणी प्रारंभ और समाप्ति तिथि (जाहिर है, datetime.date() उदाहरणों द्वारा निर्धारित की जाती है)। दो श्रेणियां ओवरलैप हो सकती हैं या नहीं। मुझे ओवरलैप के दिनों की संख्या चाहिए। निस्संदेह मैं दोनों श्रेणियों के भीतर सभी तिथियों के साथ दो सेट पूर्व-भर सकता हूं और एक सेट चौराहे का प्रदर्शन कर सकता हूं लेकिन यह संभवतः अक्षम है ... क्या सभी मामलों को कवर करने वाले लंबे समय तक अगर एलीफ सेक्शन का उपयोग करके एक और समाधान से अलग बेहतर तरीका है?पाइथन में कुशल तिथि सीमा ओवरलैप गणना?

उत्तर

108
  • दो आरंभ तिथियों में से नवीनतम और दो समाप्ति तिथियों में से सबसे पहले निर्धारित करें।
  • उन्हें घटाने के द्वारा timedelta की गणना करें।
  • यदि डेल्टा सकारात्मक है, तो ओवरलैप के दिनों की संख्या है।

यहाँ एक उदाहरण गणना है:

>>> from datetime import datetime 
>>> from collections import namedtuple 
>>> Range = namedtuple('Range', ['start', 'end']) 

>>> r1 = Range(start=datetime(2012, 1, 15), end=datetime(2012, 5, 10)) 
>>> r2 = Range(start=datetime(2012, 3, 20), end=datetime(2012, 9, 15)) 
>>> latest_start = max(r1.start, r2.start) 
>>> earliest_end = min(r1.end, r2.end) 
>>> delta = (earliest_end - latest_start).days + 1 
>>> overlap = max(0, delta) 
>>> overlap 
52 
+2

उत्कृष्ट उत्तर –

+7

+1 'रेंज' नामक tuple बनाने के लिए +1 :-) – GaretJax

+1

सुरुचिपूर्ण कोड के लिए +1। मैंने अभी यह दिनचर्या ली और इसे मेरे PHP ऐप में इस्तेमाल किया। – Eric

3

स्यूडोकोड:

1 + max(-1, min(a.dateEnd, b.dateEnd) - max(a.dateStart, b.dateStart)) 
6

समारोह कॉल अंकगणितीय आपरेशनों से ज्यादा महंगे हैं।

ऐसा करने का सबसे तेज़ तरीका 2 subtractions और 1 मिनट() शामिल है:

min(r1.end - r2.start, r2.end - r1.start).days + 1 

अगला सबसे अच्छा जो 1 घटाव, 1 मिनट() और एक अधिकतम() की जरूरत है के साथ तुलना में:

(min(r1.end, r2.end) - max(r1.start, r2.start)).days + 1 

बेशक दोनों अभिव्यक्तियों के साथ आपको अभी भी एक सकारात्मक ओवरलैप की जांच करने की आवश्यकता है।

+1

यह विधि हमेशा सही उत्तर नहीं देगी। जैसे'रेंज = नामित ('रेंज', ['स्टार्ट', 'एंड']) आर 1 = रेंज (स्टार्ट = डेटटाइम (2016, 6, 15), एंड = डेटाटाइम (2016, 6, 15)) आर 2 = रेंज (प्रारंभ = डेटाटाइम (2016, 6, 11), अंत = डेटाटाइम (2016, 6, 18)) प्रिंट मिनट (r1.end - r2.start, r2.end - r1.start)। दिन + 1' प्रिंट करेगा 4 जहां यह 1 – tkyass

0
def get_overlap(r1,r2): 
    latest_start=max(r1[0],r2[0]) 
    earliest_end=min(r1[1],r2[1]) 
    delta=(earliest_end-latest_start).days 
    if delta>0: 
     return delta+1 
    else: 
     return 0 
0

मैंने टाइमरेंज क्लास को कार्यान्वित किया जैसा कि आप नीचे देख सकते हैं।

get_overlapped_range पहले सभी गैर ओवरलैप्ड विकल्पों को एक साधारण स्थिति से अस्वीकार करता है, और फिर सभी संभावित विकल्पों पर विचार करके ओवरलैप्ड रेंज की गणना करता है।

वर्ग TimeRange (वस्तु):

def __init__(self, start, end): 
    self.start = start 
    self.end = end 
    self.duration = self.end - self.start 

def is_overlapped(self, time_range): 
    if max(self.start, time_range.start) < min(self.end, time_range.end): 
     return True 
    else: 
     return False 

def get_overlapped_range(self, time_range): 
    if not self.is_overlapped(time_range): 
     return 

    if time_range.start >= self.start: 
     if self.end >= time_range.end: 
      return TimeRange(time_range.start, time_range.end) 
     else: 
      return TimeRange(time_range.start, self.end) 
    elif time_range.start < self.start: 
     if time_range.end >= self.end: 
      return TimeRange(self.start, self.end) 
     else: 
      return TimeRange(self.start, time_range.end) 

def __repr__(self): 
    return '{0} ------> {1}'.format(*[time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(d)) 
             for d in [self.start, self.end]]) 

दिनों की राशि है जो आप TimeRange मूल्य कि get_overlapped_range से लौटाए गए लेने के लिए और 60 * 60 * 24 (द्वारा अवधि को विभाजित करने की आवश्यकता होगी पाने के लिए

+0

प्रिंट करने के लिए प्रतीत होता है ओपी के मुद्दे के लिए पहले से ही एक आदर्श समाधान है। –

संबंधित मुद्दे