Skip to content

Instantly share code, notes, and snippets.

@syminical
Last active April 1, 2021 01:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syminical/b2c20ea4ee26889bff707d89e4d9bf2e to your computer and use it in GitHub Desktop.
Save syminical/b2c20ea4ee26889bff707d89e4d9bf2e to your computer and use it in GitHub Desktop.
Scheduling Matchup - I paused the video around 9 min and solved the problem. :) https://youtu.be/kbwk1Tw3OhE
# https://youtu.be/kbwk1Tw3OhE
# I paused the video around 9 min and solved the problem. :)
# Take a time tuple and return a 2-tuple of ints representing the length of the input meeting.
# e.g. ('10:00', '10:30') => (0, 30)
def meeting_len(meeting):
start = meeting[0].split(':')
end = meeting[1].split(':')
return (abs(int(end[0])-int(start[0])), abs(int(end[1])-int(start[1])))
# Take a 2-tuple representing a single time string and return a correctly formatted string representation.
# This gets around the single digit conversion issue, and it's important to allow comparisons of time strings:
# e.g. (9, 30) => '09:30', not '9:30'
def time_str(time):
_ = [ f'0{i}' if i < 10 else str(i) for i in time ]
return ':'.join(_)
# Take a list of time tuples, and a tuple containing the start/end time constraints.
# Return a list of time tuples representing the free time gaps between the time tuples in the input list.
def free_gaps(cal, ends):
ret = []
if not cal:
return ends
if ends[0] < cal[0][0]:
ret.append((ends[0], cal[0][0]))
for i in range(len(cal)-1):
ret.append((cal[i][1], cal[i+1][0]))
if cal[-1][1] < ends[1]:
ret.append((cal[-1][1], ends[1]))
return ret
# Curried function designed to be used with the filter() function.
# Takes a minimum time length that meetings must be to pass the filter.
# Returns a function that accepts a time tuple that gets tested for the target minimum time length.
def min_time(target):
def f(meeting):
h, m = meeting_len(meeting)
return int(h) > 0 or int(m) >= target
return f
# Take two time tuples and check if they have any intersection. (time in common)
# Return a time tuple representing the amount of time in common, or None.
def gap_intersection(a, b):
if (a[0] < b[1] and b[0] < a[1]):
return (max(a[0], b[0]), min(a[1], b[1]))
return None
def main():
target_meeting_len = 30
# person a
cal_a = [('9:00', '10:30'), ('12:00','13:00'), ('14:00', '14:20'), ('14:40', '14:45'), ('16:00', '18:00')]
ends_a = ('9:00', '20:00')
# person b
cal_b = [('10:00', '11:30'), ('12:30', '14:30'), ('14:30', '15:00'), ('16:00', '17:00')]
ends_b = ('10:00', '18:30')
# Find gaps of free time in a schedule, and filter out gaps shorter than the target meeting length.
possible_a = filter(min_time(target_meeting_len), free_gaps(cal_a, ends_a))
possible_b = filter(min_time(target_meeting_len), free_gaps(cal_b, ends_b))
# Find shared gaps of time between two lists of free time gaps, and filter out gaps shorter than the target meeting length.
# This loop iterates through two lists, so it's really two while loops in one with a composite iterator.
potential_ab = []
gap_a, gap_b = next(possible_a, None), next(possible_b, None)
while gap_a and gap_b:
# Check for intersection between two free time gaps, and collect gap if there is an intersection.
if _ := gap_intersection(gap_a, gap_b):
potential_ab.append(_)
# Advance iterator(s)
if (gap_a[0] <= gap_b[0]):
gap_a = next(possible_a, None)
if (gap_b[0] <= gap_a[0]):
gap_b = next(possible_b, None)
# Filter the collected common free time gaps and return the list of common free time gaps where a meeting with the length can fit.
return list(filter(min_time(target_meeting_len), potential_ab))
if __name__ == "__main__":
print(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment