Late to the party, as usual.
day01.erl:
-module(day01).
-include_lib("eunit/include/eunit.hrl").
-export([p1/1, p2/1]).
p1(InputData) ->
[As, Bs] = transpose_input(InputData),
lists:sum([abs(A - B) || {A, B} <- lists:zip(lists:sort(As), lists:sort(Bs))]).
p2(InputData) ->
[As, Bs] = transpose_input(InputData),
lists:sum([A * length([B || B <- Bs, A =:= B]) || A <- As]).
transpose_input(InputData) ->
util:transpose([util:str_to_ints(Row) || Row <- InputData]).
gen_test_() ->
{setup, fun read_input/0, fun check_results/1}.
read_input() ->
{
util:read_input(?MODULE_STRING ++ "_test.txt"),
util:read_input(?MODULE_STRING ++ "_input.txt")
}.
check_results({TestData, InputData}) ->
[
?_assertEqual(11, p1(TestData)),
?_assertEqual(31, p2(TestData)),
?_assertEqual(2192892, p1(InputData)),
?_assertEqual(22962826, p2(InputData))
].
util.erl:
-module(util).
-export([read_input/1, str_to_ints/1, transpose/1]).
-spec read_input(Name) -> Lines when
Name :: string(),
Lines :: [string()].
read_input(Name) ->
File = filename:join([code:priv_dir(escratch), Name]),
{ok, S} = file:open(File, [read]),
read_lines(S, []).
read_lines(S, Lines) ->
case file:read_line(S) of
{ok, Line} ->
read_lines(S, [string:trim(Line) | Lines]);
eof ->
file:close(S),
lists:reverse(Lines)
end.
-spec str_to_ints(S) -> Ints when
S :: string(),
Ints :: [integer()].
str_to_ints(S) ->
[list_to_integer(X) || X <- string:tokens(S, " ")].
-spec transpose(Matrix1) -> Matrix2 when
Matrix1 :: [nonempty_list()],
Matrix2 :: [nonempty_list()].
transpose([[] | _]) -> [];
transpose(M) -> [lists:map(fun hd/1, M) | transpose(lists:map(fun tl/1, M))].