Skip to content

Instantly share code, notes, and snippets.

@KamilLelonek
Created May 26, 2018 16:05
Show Gist options
  • Save KamilLelonek/7a5acf3d18f90c23c270e15978ee2b57 to your computer and use it in GitHub Desktop.
Save KamilLelonek/7a5acf3d18f90c23c270e15978ee2b57 to your computer and use it in GitHub Desktop.
defmodule Task2 do
@doc """
Problem:
We would like to check what users are actively using one of our web applications and, if so, ask for their opinion.
Each user enters the application and navigates between pages.
For each user, we log whenever he or she opens main page or any other page.
Whenever he or she open a page for the first time or after a break of at least 30 minutes,
we count it as a new session. We will ask the user for his or her opinion
only when for the last three days he or she used the application each day
and in total he or she has had six unique sessions.
Task:
Write a function that will receive the log, i.e. a sequence of timestamps in chronological order.
Each timestamp denotes single time the user has opened the website.
The function should return True if we should ask the user for his or her opinion and False otherwise.
Timestamps are strings in the format of 'YYY-MM-DD hh:mm:ss', using user's time zone.
You can assume that the last entry is with today's date.
"""
@max_age 3 * 24 * 60 * 60
@min_duration 30 * 60
@spec call(datetimes :: [String.t()]) :: boolean()
def call(datetimes) when is_list(datetimes) do
datetimes
|> Enum.map(&to_datetime/1)
|> reject_too_old()
|> count_unique()
|> maybe_count_sessions()
|> should_ask?()
end
defp to_datetime(string) do
with {:ok, datetime, _} <- DateTime.from_iso8601("#{string}Z"), do: datetime
end
defp reject_too_old(datetimes),
do: Enum.reject(datetimes, &too_old?(List.last(datetimes), &1))
defp too_old?(today, datetime), do: DateTime.diff(today, datetime) > @max_age
defp count_unique(datetimes),
do: {datetimes, unique_days_count(datetimes)}
defp unique_days_count(datetimes) do
datetimes
|> Enum.uniq_by(&DateTime.to_date/1)
|> Enum.count()
end
defp maybe_count_sessions({_datetimes, unique_count}) when unique_count < 3, do: false
defp maybe_count_sessions({datetimes, _unique_count}) do
datetimes
|> Enum.chunk_every(2)
|> Enum.map(&session?/1)
|> Enum.count(& &1)
end
defp session?([_datetime]), do: true
defp session?([d1, d2]), do: DateTime.diff(d2, d1) > @min_duration
defp should_ask?(false), do: false
defp should_ask?(count) when count < 3, do: false
defp should_ask?(_count), do: true
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment