-
-
Save fschuindt/e008bd05c9dda4ab050dcf0c7b824198 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule SunLightExperiment do | |
@moduledoc false | |
alias Decimal, as: D | |
require Logger | |
@doc false | |
def perform do | |
with data <- read_data("data.csv"), | |
starts_growth <- compute_growth(data, :starts), | |
ends_growth <- compute_growth(data, :ends), | |
size_growth <- compute_growth(data, :size), | |
starts_growth_average <- average(starts_growth), | |
ends_growth_average <- average(ends_growth), | |
size_growth_average <- average(size_growth) do | |
Logger.info("Printing results...") | |
IO.inspect(data) | |
IO.puts("\n'starts' growth: #{inspect(starts_growth)}\n") | |
IO.puts("'ends' growth: #{inspect(ends_growth)}\n") | |
IO.puts("'size' growth: #{inspect(size_growth)}\n") | |
IO.puts("'starts' growth average: #{inspect(starts_growth_average)}\n") | |
IO.puts("'ends' growth average: #{inspect(ends_growth_average)}\n") | |
IO.puts("'size' growth average: #{inspect(size_growth_average)}") | |
end | |
end | |
@spec read_data(String.t()) :: Enumerable.t() | |
defp read_data(file) do | |
file | |
|> File.stream!() | |
|> CSV.decode() | |
|> Stream.take(10) | |
|> Stream.map(&get_valid_row/1) | |
|> Stream.drop(1) | |
|> Stream.map(&trim_columns/1) | |
|> Stream.map(&to_entry/1) | |
|> Enum.filter(fn entry -> entry != %{} end) | |
end | |
@spec compute_growth(list(map()), atom()) :: list(D.t()) | |
defp compute_growth(results, v) do | |
Enum.reduce(results, [], fn result, acc -> | |
case result == Enum.at(results, 0) do | |
true -> | |
acc | |
_any -> | |
acc ++ [D.sub(Map.get(result, v), tnm1(results, v, Enum.count(acc) + 1))] | |
end | |
end) | |
end | |
@spec average(list(D.t())) :: D.t() | |
defp average(list) do | |
with count <- Enum.count(list), | |
count <- D.new(count), | |
sum <- Enum.reduce(list, D.new(0), fn e, acc -> D.add(e, acc) end) do | |
D.div(sum, count) | |
end | |
end | |
@spec tnm1(list(map()), atom(), integer()) :: D.t() | |
defp tnm1(results, variable, n) do | |
results | |
|> Enum.at(n - 1) | |
|> Map.get(variable) | |
end | |
@spec get_valid_row({:ok, list(String.t())} | any()) :: list(String.t()) | |
defp get_valid_row(result) do | |
case result do | |
{:ok, row} -> row | |
_any -> [] | |
end | |
end | |
@spec to_entry(list(String.t())) :: {:ok, Entry.t()} | {:error, Error.t()} | |
defp to_entry([id, filename, taken_at, starts, ends]) do | |
with {:ok, taken_at, _offset} <- DateTime.from_iso8601(taken_at), | |
{starts, _any} <- D.parse(starts), | |
{ends, _any} <- D.parse(ends), | |
entry <- do_to_entry(id, filename, taken_at, starts, ends) do | |
entry | |
end | |
end | |
defp to_entry(_any) do | |
%{} | |
end | |
@spec do_to_entry(String.t(), String.t(), DateTime.t(), D.t(), D.t()) :: map() | |
defp do_to_entry(id, filename, taken_at, starts, ends) do | |
%{ | |
id: id, | |
filename: filename, | |
taken_at: taken_at, | |
starts: starts, | |
ends: ends, | |
size: D.sub(ends, starts) | |
} | |
end | |
@spec trim_columns(list(String.t())) :: list(String.t()) | |
defp trim_columns(row) do | |
Enum.map(row, fn | |
column when is_binary(column) -> String.trim(column) | |
column -> column | |
end) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment