在给定端点和端点之间的某些点的情况下,是否存在更优雅的方法来确定互斥/穷举间隔?
以下测试以一个月的计费期以及该月内的几个点或区间划分来描述该方案。我想得到一个成对的列表,详细列出由给定的边界导致的各个间隔。
def test_fill_time_gaps(self):
bill_period = (localtz_parse('2018-03-01'), localtz_parse('2018-03-31'))
# test fill first gap
periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-31'))])
self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
(localtz_parse('2018-03-04'), localtz_parse('2018-03-31'))])
periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
(localtz_parse('2018-03-05'), localtz_parse('2018-03-31'))])
self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
(localtz_parse('2018-03-05'), localtz_parse('2018-03-31'))])
# test fill first and last gap
periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-15'))])
self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
(localtz_parse('2018-03-04'), localtz_parse('2018-03-15')),
(localtz_parse('2018-03-15'), localtz_parse('2018-03-31'))])
# test fill first gap and gap in between
periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
(localtz_parse('2018-03-08'), localtz_parse('2018-03-31'))])
self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
(localtz_parse('2018-03-05'), localtz_parse('2018-03-08')),
(localtz_parse('2018-03-08'), localtz_parse('2018-03-31'))])
# test fill first gap and gap in between and last gap
periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
(localtz_parse('2018-03-08'), localtz_parse('2018-03-15'))])
self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
(localtz_parse('2018-03-05'), localtz_parse('2018-03-08')),
(localtz_parse('2018-03-08'), localtz_parse('2018-03-15')),
(localtz_parse('2018-03-15'), localtz_parse('2018-03-31'))])
这是我最初的尝试:
def fill_time_gaps(boundary, periods):
"""
Given a period boundary, fill in gaps within given periods
Assuming periods are in seqential order
:param boundary: period boundry
:param periods: sequence of periods, should contain at least one period
:return: sequence of periods with filled gaps
"""
if not len(periods):
raise Exception('periods should contain at least one period')
# works by stepping through the periods and compare the against the way-point
# to determine if there is a gap
result = []
bound_start, bound_end = boundary
way_point = bound_start
for period in periods:
period_start, period_end = period
if period_start > way_point:
gap = (way_point, period_start)
result.append(gap)
result.append(period)
way_point = period_end
# fill the last gap
if way_point < bound_end:
result.append((way_point, bound_end))
return result
但是这似乎有点“愚蠢”(有时愚蠢的代码是好的代码,但在这种情况下不确定),我不确定这是否也是防弹的,但它可以通过我现有的测试。
我渴望知道是否有更好的解决方法?
答案 0 :(得分:1)
由于填充逻辑实际上并不依赖于日期时间表示形式,因此为了便于理解,我将其缩减为日期数字。
代码:
def fill_time_gaps(boundary, periods):
bound = sorted(list(set(boundary + periods)))
return tuple([(post, bound[i+1]) for i, post in enumerate(bound[:-1])])
billing = (1, 31)
test = [(2, 3),
(1, 8),
(10, 31),
(4, 5, 12)]
for case in test:
print(fill_time_gaps(billing, case))
输出:
((1, 2), (2, 3), (3, 31))
((1, 8), (8, 31))
((1, 10), (10, 31))
((1, 4), (4, 5), (5, 12), (12, 31))