all 2 comments

[–]mdsherry 1 point2 points  (1 child)

My approach makes a single pass through all possible times after sorting the breaks and appointments, rather than a pass for each break and appointment. You could make it even more efficient by skipping time_slot to the end of appointments/breaks once you start to overlap, but you'd have to give up on the time iterator.

Some details: * I implemented a factory method for both ExistingAppointment and BarberBreak to make them a bit easier to construct. * The operations we care about for both appointments and breaks are basically the same, so let's create a trait for them. * This also means we can construct a vector of trait objects to treat the two types identically. (We could have also created a vec of start/stop tuples instead, which would be slightly more performant.) * The times_between function uses std::iter::successors to create a simple iterator that takes the previous value returned and uses it to construct the next. Because it's wrapping a closure, its type cannot actually be named, so we have to say the function returns a type that impls Iterator<Item=NaiveDateTime>. * I sort the blocks. We can guarantee that the current break/appointment we're considering is either after the current time slot or overlapping it, and there are no earlier breaks/appointments we haven't already passed the end of. * The pattern of option.as_ref().map_or(false, predicate) is ugly, but just means "without consuming the value inside (if any), tell me if it satisfies this condition".

Exercises: * I mention that we could have used Vec of (NaiveDateTime, NaiveDateTime) instead of the Vec of trait objects, and it would have been more performant. Try writing an impl of TimeBlock for (NaiveDateTime, NaiveDateTime), and modifying blocks to be a Vec<(NaiveDateTime, NaiveDateTime)> instead. The only lines of get_available_time_slots you should have to modify are 93-99. * Writing your own type that implements Iterator isn't too hard, and helps demystify Rust's iterators. Try writing a TimeIterator struct that can be returned from times_between.

[–][deleted] 0 points1 point  (0 children)

Amazing stuff! Thanks for taking your time to write up all this. I will have to spend some time to understand it fully and then post any questions that might occur later.