1
votes

I have two lists of tuples that contain start and end times. All the start and end times are Time structs.

I want to filter out the time_slots that overlap with any booked_slots:

time_slots = [
  {~T[09:00:00], ~T[17:00:00]},
  {~T[13:00:00], ~T[17:00:00]},
  {~T[13:00:00], ~T[21:00:00]},
  {~T[17:00:00], ~T[21:00:00]},
  {~T[09:00:00], ~T[13:00:00]},
  {~T[09:00:00], ~T[21:00:00]}
]

booked_slots = [{~T[14:00:00], ~T[21:00:00]}]

Which should leave us with:

[
  {~T[09:00:00], ~T[13:00:00]}
]

I have tried the following method (as adapted from the answer to a previous related question: Compare two lists to find date and time overlaps in Elixir):

Enum.filter(time_slots, fn {time_start, time_end} ->
  Enum.any?(booked_slots, fn {booking_start, booking_end} ->
    if Time.compare(booking_start, time_start) == :lt do
      Time.compare(booking_end, time_start) == :gt
    else
      Time.compare(booking_start, time_end) == :lt
    end
  end)
end)

However this returns:

[
  {~T[09:00:00], ~T[17:00:00]},
  {~T[13:00:00], ~T[17:00:00]},
  {~T[13:00:00], ~T[21:00:00]},
  {~T[17:00:00], ~T[21:00:00]},
  {~T[09:00:00], ~T[21:00:00]}
]

We also need to factor in times that may be equal, but do not overlap. For example:

time_slots = [
  {~T[09:00:00], ~T[17:00:00]},
  {~T[13:00:00], ~T[17:00:00]},
  {~T[13:00:00], ~T[21:00:00]},
  {~T[17:00:00], ~T[21:00:00]},
  {~T[09:00:00], ~T[21:00:00]},
  {~T[09:00:00], ~T[13:00:00]}
]

booked_slots = [{~T[17:00:00], ~T[21:00:00]}]

Should return…

[
  {~T[09:00:00], ~T[17:00:00]},
  {~T[13:00:00], ~T[17:00:00]},
  {~T[09:00:00], ~T[13:00:00]}
]
1
What is the reason to repost your own perfectly answered questions? - Aleksei Matiushkin
@AlekseiMatiushkin I have tried adapting the answer from my previous question (which I am well aware of and have been working with for the past hour). However it does not yield the result I am looking for. More info provided in my question for clarity. - gosseti

1 Answers

3
votes

You need to filter out all the time slots having either start or end times inside the booked slot.

Enum.reject(time_slots, fn {ts, te} ->
  Enum.any?(booked_slots, fn {bs, be} ->
    (Time.compare(ts, bs) != :lt and Time.compare(ts, be) == :lt) or
    (Time.compare(te, bs) == :gt and Time.compare(te, be) != :gt) or
    (Time.compare(ts, bs) == :lt and Time.compare(te, be) == :gt)
  end)
end)

The first condition checks for slots having start time inside the booked slot, the second one checks for those having end time within the booked slots, and the third one checks for those containing the whole booked slot.