作为运行预订系统的某些代码的一部分,我们有一个time_slots
列表,它们是包含{start_time, end_time}
的元组。这些是可以预订的可用时隙:
time_slots = [
{~T[09:00:00], ~T[13:00:00]},
{~T[09:00:00], ~T[17:00:00]},
{~T[09:00:00], ~T[21: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]}
]
然后,我们还有一个预订列表,其中包含每个{booking_start, booking_end}
的元组列表。
bookings = [
[
{~N[2019-06-13 09:00:00], ~N[2019-06-13 17:00:00]},
{~N[2019-06-13 17:00:00], ~N[2019-06-13 21:00:00]}
],
[{~N[2019-06-20 09:00:00], ~N[2019-06-20 21:00:00]}],
[
{~N[2019-06-22 13:00:00], ~N[2019-06-22 17:00:00]},
{~N[2019-06-22 17:00:00], ~N[2019-06-22 21:00:00]}
]
]
在这种情况下,我们希望结果为两个time_slots
都已填写的预订:
2019-06-13
2019-06-20
因为所有时隙都已填满,然后以Date
的形式返回这些结果。
要提供更多信息:
0900–1000
将填补0900–1300
,0900–1700
和0900–2100
的时间段0900–1000
和1000–1200
,这两个预订都可以在0900–1300
时段内使用。0800—2200
的预订将填补0900–2100
的时间段(以及所有其他时间段)答案 0 :(得分:2)
所以我对这个问题的理解是:对于预订列表,所有时隙是否至少与一个预订冲突?
可以通过检查以下两项来回答有冲突的预订:
如果在时间段开始之前开始预订,则如果在时间段开始之后完成预订则发生冲突。
如果在时间段开始或之后开始预订,则如果在时间段结束之前开始预订,则发生冲突。
因此,工作代码如下:
time_slots = [
{~T[09:00:00], ~T[13:00:00]},
{~T[09:00:00], ~T[17:00:00]},
{~T[09:00:00], ~T[21: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]}
]
bookings = [
[
{~N[2019-06-13 09:00:00], ~N[2019-06-13 17:00:00]},
{~N[2019-06-13 17:00:00], ~N[2019-06-13 21:00:00]}
],
[{~N[2019-06-20 09:00:00], ~N[2019-06-13 21:00:00]}],
[
{~N[2019-06-22 13:00:00], ~N[2019-06-22 17:00:00]},
{~N[2019-06-22 17:00:00], ~N[2019-06-22 21:00:00]}
]
]
bookings
|> Enum.filter(fn booking ->
Enum.all?(time_slots, fn {time_start, time_end} ->
Enum.any?(booking, 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)
end)
|> Enum.map(fn [{booking_start, _} | _] -> NaiveDateTime.to_date(booking_start) end)
PS:请注意,您不应将时间/日期/日期时间与>
,<
和朋友进行比较。始终使用相关的比较功能。
答案 1 :(得分:1)
尽管这可能无法涵盖所有情况,但鉴于您提供的示例数据可以正常工作
defmodule BookingsTest do
@slots [
{~T[09:00:00], ~T[13:00:00]},
{~T[09:00:00], ~T[17:00:00]},
{~T[09:00:00], ~T[21: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]}
]
def booked_days(bookings, time_slots \\ @slots) do
Enum.reduce(bookings, [], fn(day_bookings, acc) ->
Enum.reduce(day_bookings, time_slots, fn({%{hour: s_time}, %{hour: e_time}}, ts) ->
Enum.reduce(ts, [], fn
({%{hour: slot_s}, %{hour: slot_e}} = slot, inner_acc) ->
case is_in_slot(s_time, e_time, slot_s, slot_e) do
true -> inner_acc
_ -> [slot | inner_acc]
end
end)
end)
|> case do
[] -> [day_bookings | acc]
_ -> acc
end
end)
|> Enum.reduce([], fn([{arb, _} | _], acc) -> [NaiveDateTime.to_date(arb) | acc] end)
end
def is_in_slot(same_start, _, same_start, _), do: true
def is_in_slot(s_time, e_time, slot_s, slot_e) when s_time < slot_s and e_time > slot_s, do: true
def is_in_slot(s_time, e_time, slot_s, slot_e) when s_time > slot_s and s_time < slot_e, do: true
def is_in_slot(_, _, _, _), do: false
end
> bookings = [
[
{~N[2019-06-13 10:00:00], ~N[2019-06-13 17:00:00]},
{~N[2019-06-13 17:00:00], ~N[2019-06-13 21:00:00]}
],
[{~N[2019-06-20 09:00:00], ~N[2019-06-20 21:00:00]}],
[
{~N[2019-06-22 13:00:00], ~N[2019-06-22 17:00:00]},
{~N[2019-06-22 17:00:00], ~N[2019-06-22 21:00:00]}
]
]
> BookingsTest.booked_days(bookings)
[~D[2019-06-13], ~D[2019-06-20]]
这个想法是,通过将bookings
列表减少为一个空列表,每个枚举将成为当天已占用广告位的列表。
减少此列表,累积所有可用时隙的列表。
在此过程中,通过时隙累加器将其减少到一个空列表中。
对于每个时段,请检查当天预订时段的开始时间和结束时间是否与该时段重叠。如果确实存在,则仅按原样返回内部累加器。如果没有,请将插槽添加到此累加器中。
在day_bookings
减少的最后,如果您有一个空白列表,则表示当天没有空位。因此,将其添加到外部累加器中,这将是已满的天数的列表。
最后,您再次减少结果,以便将其取反,然后在此过程中将每个元素设置为Date,而不是当天的预订列表。
答案 2 :(得分:1)
假设您在第二次预订中遇到错字,并且在自己结束后不到 个星期后才开始输入错,那么解决方案可能比认真减少方案简单得多。
在预定开始和结束时的确切位置上的空位已满:
{start, end} =
time_slots
|> Enum.flat_map(&Tuple.to_list/1)
|> Enum.min_max()
#⇒ {~T[09:00:00], ~T[21:00:00]}
这使支票几乎微不足道:
Enum.filter(bookings, fn booking ->
{s, e} = {Enum.map(booking, &elem(&1, 0)), Enum.map(booking, &elem(&1, 1))}
with {[s], [e]} <- {s -- e, e -- s} do
same_date =
[s, e]
|> Enum.map(&NaiveDateTime.to_date/1)
|> Enum.reduce(&==/2)
full = Enum.map([s, e], &NaiveDateTime.to_time/1)
same_date and full == [start, end]
end
end)
Kernel.SpecialForms.with/1
保证将过滤掉所有不期望的内容。