ijunaidfarooq
Not a Code Review but asking Suggestions
I have 2 code snippets that actually do the same job.
- is a bit complicated but solve the problem
- is bt cleaner and solve the same problem
I have this test data set.
[
%{day: "mon", since: ~T[01:00:00], till: ~T[01:55:00]},
%{day: "mon", since: ~T[02:00:00], till: ~T[02:55:00]},
%{day: "mon", since: ~T[03:00:00], till: ~T[03:55:00]},
%{day: "tue", since: ~T[01:00:00], till: ~T[01:55:00]},
%{day: "tue", since: ~T[02:00:00], till: ~T[02:55:00]},
%{day: "tue", since: ~T[03:00:00], till: ~T[03:55:00]},
%{day: "wed", since: ~T[01:00:00], till: ~T[01:55:00]},
%{day: "wed", since: ~T[02:00:00], till: ~T[02:55:00]},
%{day: "wed", since: ~T[03:00:00], till: ~T[03:55:00]},
%{day: "thu", since: ~T[01:00:00], till: ~T[01:55:00]},
%{day: "thu", since: ~T[02:00:00], till: ~T[02:55:00]},
%{day: "thu", since: ~T[03:00:00], till: ~T[03:55:00]},
%{day: "fri", since: ~T[01:00:00], till: ~T[01:55:00]},
%{day: "fri", since: ~T[02:00:00], till: ~T[02:55:00]},
%{day: "fri", since: ~T[03:00:00], till: ~T[03:55:00]},
%{day: "sat", since: ~T[01:00:00], till: ~T[01:55:00]},
%{day: "sat", since: ~T[02:00:00], till: ~T[02:55:00]},
%{day: "sat", since: ~T[03:00:00], till: ~T[03:55:00]},
%{day: "sun", since: ~T[01:00:00], till: ~T[01:55:00]},
%{day: "sun", since: ~T[02:00:00], till: ~T[02:55:00]},
%{day: "sun", since: ~T[03:00:00], till: ~T[03:55:00]}
]
Problem: I want to show you the first available time from the above timeslots to meet me depending on today’s day.
First solution bit complex.
defmodule TestAvailabilityHours do
@days ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
@days_with_indexes Enum.zip(1..7, @days) |> Map.new()
def days(), do: @days
def days_with_indexes(), do: @days_with_indexes
def get_first_available() do
doctors_availability_hours = dummy_timeslots()
case length(doctors_availability_hours) > 0 do
true ->
current_day =
DateTime.utc_now()
|> get_day_name()
first_timeslot =
doctors_availability_hours
|> Enum.filter(&(&1.day == current_day))
|> no_day_present(doctors_availability_hours, current_day)
|> get_datetime_from_hour()
{:ok, first_timeslot}
_ ->
{:error, :no_timeslots_found}
end
end
defp no_day_present([], hours, day) do
hours
|> Enum.chunk_every(2, 1, :discard)
|> Enum.reverse()
|> Enum.find_value(fn [%{day: d}, next] -> if d == day, do: next end)
|> no_more_days_left(hours)
end
defp no_day_present(hour, _, _), do: hour |> List.first()
defp no_more_days_left(nil, hours), do: hours |> List.first()
defp no_more_days_left(hour, _hours), do: hour
defp get_datetime_from_hour(hour) do
Enum.reduce_while(1..7, Date.utc_today(), fn _day, acc ->
current_day =
acc
|> get_day_name()
if current_day != hour.day,
do: {:cont, Timex.shift(acc, days: 1)},
else: {:halt, acc}
end)
|> NaiveDateTime.new(hour.since)
|> elem(1)
|> DateTime.from_naive!("Etc/UTC")
end
defp get_day_name(datetime) do
datetime
|> Timex.weekday()
|> Timex.day_shortname()
|> String.downcase()
end
def dummy_timeslots() do
Enum.flat_map(1..7, fn day ->
Enum.map(1..3, fn hour ->
since = "0#{hour}:00:00"
till = "0#{hour}:55:00"
%{
day: days_with_indexes()[day],
since: Time.from_iso8601!(since),
till: Time.from_iso8601!(till)
}
end)
end)
end
end
and now 2nd solution.
defmodule TestAvailabilityHours do
@days ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
@days_with_indexes Enum.zip(1..7, @days) |> Map.new()
def days(), do: @days
def days_with_indexes(), do: @days_with_indexes
def test() do
datetime = DateTime.utc_now
weekday = Date.day_of_week(datetime)
time = DateTime.to_time(datetime)
availability_timeslots = dummy_timeslots()
closest_timeslot =
Enum.find(availability_timeslots, fn timeslot ->
timeslot_day_index = Timex.day_to_num(timeslot.day)
cond do
timeslot_day_index == weekday ->
time >= timeslot.since && time < timeslot.till
timeslot_day_index > weekday ->
true
timeslot_day_index < weekday ->
false
end
end)
next_monday_beginning =
datetime |> Timex.end_of_week() |> Timex.shift(seconds: 1)
next_closest_timeslot = List.first(availability_timeslots)
timeslot_to_datetime(closest_timeslot, datetime) ||
timeslot_to_datetime(next_closest_timeslot, next_monday_beginning)
end
def timeslot_to_datetime(nil, _), do: nil
def timeslot_to_datetime(timeslot, datetime) do
weekday_index = Date.day_of_week(datetime)
date = DateTime.to_date(datetime)
timeslot_day_index = Timex.day_to_num(timeslot.day)
cond do
weekday_index == timeslot_day_index ->
NaiveDateTime.new(date, timeslot.since)
weekday_index < timeslot_day_index ->
date = Timex.shift(date, days: timeslot_day_index - weekday_index)
NaiveDateTime.new(date, timeslot.since)
end
end
def dummy_timeslots() do
Enum.flat_map(1..7, fn day ->
Enum.map(1..3, fn hour ->
since = "0#{hour}:00:00"
till = "0#{hour}:55:00"
%{
day: days_with_indexes()[day],
since: Time.from_iso8601!(since),
till: Time.from_iso8601!(till)
}
end)
end)
end
end
I already know the 2nd solution is the better one. But can you suggest to me if I can still do better with it? is there any more easy way than this to solve this problem?
also how I can test both methods with regards to time? I mean which is more performant?
Most Liked
andreyuhai
Well, not sure whether this would be helpful but anyway.
You could have the days as your keys in the map so you would only have 7 different keys.
%{
mon: [%{since: ..., till: ...}],
tue: [],
...
}
That way you could get a specific day easier and from there you can work out the first available time.
Maybe even better with indexes so you can only look for indexes that are greater than or equal to today’s index.
ijunaidfarooq
You were right.
I had to add this
defp reject_old_timeslots(timeslots) do
timeslots |> Enum.reject(&Timex.before?(&1, DateTime.utc_now()))
end
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #hex
- #security









