python设置循环范围_python – 如何检查循环范围的重叠(重叠的年度循环周期)

我试图找到一个优雅的算法,以检查两个年度重复周期是否重叠.这个时期与年份无关,但一年可能总是闰年.

例如,期间A =(3月1日至5月1日)和期间B =(4月1日至9月1日)重叠.

此外,期间A =(10月1日至2月1日)和期间B =(1月1日至3月1日)重叠.

但是,我发现这比我预想的要困难得多.复杂性来自于跨越年底的时期.

我有一个有效的解决方案(参见下面的doOverlap(A,B)方法),但我发现它令人沮丧.

# for the rest of the MWE context code, see further

# WORKING, but a bit convulted

def doesOverlap(A, B):

'''returns True if yearly period A and B have overlapping dates'''

# list to track if day in year is part of a period A

# (this could probably be done a bit cheaper with a dictionary of tuples, but not relevant for my question)

yeardayCovered = [False for x in range(366)] # leap year

# mark the days of A

for d in range(A.start, A.start A.length):

yeardayCovered[d % 366] = True

# now check each of the days in B with A

for d in range(B.start, B.start B.length):

if yeardayCovered[d % 366]:

return True

return False

我相信应该可以用更少的支票和更优雅的方式来做到这一点.我已经尝试将其中一个开始日设置为零偏移,应用一些模运算符,然后是常规(非循环)范围重叠检查(Algorithm to detect overlapping periods).但我还没有为我的所有测试用例工作.

#NOT WORKING CORRECTLY!!

def doesOverlap(A, B):

'''determines if two yearly periods have overlapping dates'''

Astart = A.start

Astop = A.stop

Bstart = B.start

Bstop = B.stop

# start day counting at Astart, at 0

offset = Astart

Astart = 0

Astop = (Astop - offset) % 366

Bstart = (Bstart - offset) % 366

Bstop = (Bstop - offset) % 366

# overlap?

# https://stackoverflow.com/a/13513973

return (Astart <= Bstop and Bstart <= Astop)

注意:我已经用Python完成了代码,但理想情况下解决方案应该不是特定于Python的(即不使用通常只在Python中可用的函数,而不是在C或C#中)

# MWE (Minimal Working Example)

import datetime

import unittest

class TimePeriod:

def __init__(self, startDay, startMonth, stopDay, stopMonth):

self.startDay = startDay

self.startMonth = startMonth

self.stopDay = stopDay

self.stopMonth = stopMonth

def __repr__(self):

return "From " str(self.startDay) "/" str(self.startMonth) " to " str(self.stopDay) "/" str(self.stopMonth)

def _dayOfYear(self, d, m, y=2012):

'''2012 = leap year'''

date1 = datetime.date(year=y, day=d, month=m)

return date1.timetuple().tm_yday

@property

def start(self):

'''day of year of start of period, zero-based for easier modulo operations! '''

return self._dayOfYear(self.startDay, self.startMonth) - 1

@property

def stop(self):

'''day of year of stop of period, zero-based for easier modulo operations! '''

return self._dayOfYear(self.stopDay, self.stopMonth) - 1

@property

def length(self):

'''number of days in the time period'''

_length = (self.stop - self.start) % 366 1

return _length

def doesOverlap(A, B):

# code from above goes here

class TestPeriods(unittest.TestCase):

pass

def test_generator(a, b, c):

def test(self):

self.assertEqual(doesOverlap(a, b), c)

return test

if __name__ == '__main__':

#some unit tests, probably not complete coverage of all edge cases though

tests = [["max", TimePeriod(1, 1, 31, 12), TimePeriod(1, 1, 1, 1), True],

["BinA", TimePeriod(1, 3, 1, 11), TimePeriod(1, 5, 1, 10), True],

["BoverEndA", TimePeriod(1, 1, 1, 2), TimePeriod(10, 1, 3, 3), True],

["BafterA", TimePeriod(1, 1, 1, 2), TimePeriod(2, 2, 3, 3), False],

["sBoutA", TimePeriod(1, 12, 2, 5), TimePeriod(1, 6, 1, 7), False],

["sBoverBeginA", TimePeriod(1, 11, 2, 5), TimePeriod(1, 10, 1, 12), True],

["sBinA", TimePeriod(1, 11, 2, 5), TimePeriod(1, 1, 1, 2), True],

["sBinA2", TimePeriod(1, 11, 2, 5), TimePeriod(1, 12, 10, 12), True],

["sBinA3", TimePeriod(1, 11, 2, 5), TimePeriod(1, 12, 1, 2), True],

["sBoverBeginA", TimePeriod(1, 11, 2, 5), TimePeriod(1, 10, 1, 12), True],

["Leap", TimePeriod(29, 2, 1, 4), TimePeriod(1, 10, 1, 12), False],

["BtouchEndA", TimePeriod(1, 2, 1, 2), TimePeriod(1, 2, 1, 3), True]]

for i, t in enumerate(tests):

test_name = 'test_%s' % t[0]

test = test_generator(t[1], t[2], t[3])

setattr(TestPeriods, test_name, test)

# unittest.main()

suite = unittest.TestLoader().loadTestsFromTestCase(TestPeriods)

unittest.TextTestRunner(verbosity=2).run(suite)

解决方法:

def overlap(a0, a1, b0, b1):

首先,如果在开始日期之前结束,则可以通过调整结束日期将“年”圈中的间隔“提升”到时间“线”…

if a1 < a0: a1 = 365

if b1 < b0: b1 = 365

如果两个规则间隔相交,则存在交叉点

if a1 > b0 and a0 < b1: return True

或者如果他们确实移动[a0 … a1 [前进一年或后退一年

if a1 365 > b0 and a0 365 < b1: return True

if a1-365 > b0 and a0-365 < b1: return True

否则没有交集

return False

来源:https://www.icode9.com/content-1-361101.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值