Advent of Code 2024: Day 1
Mix.install([
{:req, "~> 0.5.8"}
])
Data
require Integer
opts = [headers: [{"cookie", "session=#{System.fetch_env!("AOC_SESSION_COOKIE")}"}]]
input = Req.get!("https://adventofcode.com/2024/day/1/input", opts).body
test_input = "3 4
4 3
2 5
1 3
3 9
3 3
"
Parser
To parse the numbers we’ll simply split on all whitespace, trim and convert to integers. We then have all the numbers in on long list, so we split into two lists on odd/even indices.
defmodule Parser do
def parse input do
nums = String.split(input,["\r\n","\n"," "],trim: true) |> Enum.map(&String.to_integer/1) |> Enum.with_index
{
Enum.filter(nums, fn {_,idx} -> Integer.is_even(idx) end) |> Enum.map(fn {num, _} -> num end),
Enum.filter(nums, fn {_,idx} -> Integer.is_odd(idx) end) |> Enum.map(fn {num, _} -> num end)
}
end
end
Parser.parse test_input
Parser.parse input
Solution
Part 1
Simply sort each list, zip them to pair them up, subtract them pairwise, take the absolute value then sum the result.
Part 2
Get the frequencies of each number in the right hand list, then simply reduce over the left list, multiplying the left list entry by the frequency of itself in the right list and summing the result.
defmodule Day1 do
def part1 input do
{left,right} = Parser.parse(input)
Enum.zip(Enum.sort(left),Enum.sort(right))
|> Enum.reduce(0, fn {a,b}, total -> total + abs(a-b) end)
end
def part2 input do
{left, right} = Parser.parse(input)
right = Enum.frequencies(right)
Enum.reduce(left, 0, fn a, total -> total + a * Map.get(right, a, 0) end)
end
end
Day1.part1 test_input
Testing
ExUnit.start(auto_run: false)
defmodule Day1Specs do
@test_input test_input
@real_input input
use ExUnit.Case, async: false
test "part 1 should return 11 for the test input" do
assert Day1.part1(@test_input) === 11
end
test "part 1 should return 1889772 for the real input" do
assert Day1.part1(@real_input) === 1889772
end
test "part 2 should return 31 for the test input" do
assert Day1.part2(@test_input) === 31
end
test "part 2 should return 23228917 for the test input" do
assert Day1.part2(@real_input) === 23228917
end
end
ExUnit.run()
Results
Part 1 Result
Day1.part1(input)
Part 2 Result
Day1.part2(input)