For a time tracking application, the day is split into five sections:
0:00 - 6:00, 6:00 - 14:00, 14:00 - 20:00, 20:00 - 23:00, 23:00 - (infinity)
These five "bins" need to be filled according to time spent in either of these. For instance the interval in question starts at 5:00 and ends at 16:00, bin #1 contains 1 hour, bin #2 contains 8 hours, bin #3 contains 2 hours, bin #4 contains 0 hours, bin #5 contains 0 hours. Any amount of time, beyond 23:00 goes into bin #5.
So far I came up with this:
sections = [ 0, 0, 0, 0, 0 ]
for tframe in numericdata:
if tframe[0] < 6.00: # starts before 6:00
if tframe[1] >= 6.00: # ends after 6:00
sections[0] += 6.00 - tframe[0]
else: # ends before 6:00
sections[0] += tframe[1] - tframe[0]
continue
if tframe[1] >= 14.00: # ends after 14:00
sections[1] += 14.00 - 6.00
else: # ends between 6:00 and 14:00
sections[1] += tframe[1] - 6.00
continue
if tframe[1] >= 20.00: # ends after 20:00
sections[2] += 20.00 - 14.00
else: # ends between 14:00 and 20:00
sections[2] += tframe[1] - 14.00
continue
if tframe[1] >= 23.00: # ends after 23:00
sections[3] += 23.00 - 20.00
sections[4] += tframe[1] - 23.00
else: # ends between 20:00 and 23:00
sections[3] += tframe[1] - 20.00
continue
elif tframe[0] < 14.00: # starts between 6:00 and 14:00
if tframe[1] >= 14.00: # ends after 14:00
sections[1] += 14.00 - tframe[0]
else: # ends before 14:00
sections[1] += tframe[1] - tframe[0]
continue
if tframe[1] >= 20.00: # ends after 20:00
sections[2] += 20.00 - 14.00
else: # ends between 14:00 and 20:00
sections[2] += tframe[1] - 14.00
continue
if tframe[1] >= 23.00: # ends after 23:00
sections[3] += 23.00 - 20.00
sections[4] += tframe[1] - 23.00
else: # ends between 20:00 and 23:00
sections[3] += tframe[1] - 20.00
continue
elif tframe[0] < 20.00: # starts between 14:00 and 20:00
if tframe[1] >= 20.00: # ends after 20:00
sections[2] += 20.00 - tframe[0]
else: # ends before 20:00
sections[2] += tframe[1] - tframe[0]
continue
if tframe[1] >= 23.00: # ends after 23:00
sections[3] += 23.00 - 20.00
sections[4] += tframe[1] - 23.00
else: # ends between 20:00 and 23:00
sections[3] += tframe[1] - 20.00
continue
elif tframe[0] < 23.00: # starts between 20:00 and 23:00
if tframe[1] >= 23.00: # ends after 23:00
sections[3] += 23.00 - tframe[0]
sections[4] += tframe[1] - 23.00
else: # ends before 23:00
sections[3] += tframe[1] - tframe[0]
continue
else: # starts and ends some time after 23:00
sections[4] += tframe[1] - tframe[0]
numericdata
is an array containing intervals as tuples of start and end times. All time values have been converted to hours with fractions, so 13:15 is encoded as 13.25, etc.
As an example numericdata
may contain [ [ 6.75, 12.5 ], [ 13.5, 18.25 ] ]
, so two intervals, one from 6:45 to 12:30, and another one from 13:30 to 18:15. The resulting sections
array would look like this: [ 0, 6.25, 4.25, 0, 0 ]
I feel like there must be a better way to do this, than what I've come up with. It's entirely hardcoded, and I can't come up with constructing something, that reduces code duplication, and perhaps is a bit more flexible, such as defining the amount of bins, and their lengths rather than hardcoding them like that.
Thanks in advance!
I hope I understood your question correctly. The split hours are defined in list splits
, so it's configurable:
data = [[ 6.75, 12.5 ], [ 13.5, 18.25 ]]
splits = [0, 6, 14, 20, 23, float('inf')]
def intersection(a, b, c, d):
if a > d or b < c:
return 0 # no intersection
left, right = max(a, c), min(b, d)
return right - left
out = [sum(v) for v in zip(*[[intersection(*i, *s) for s in zip(splits, splits[1::])] for i in data])]
print(out)
Prints:
[0, 6.25, 4.25, 0, 0]