bjorng
Erlang Core Team
Advent of Code 2025 - Day 5
Easy puzzles two days in a row. I suspect tomorrow’s puzzle will not be that easy…
defmodule Day05 do
def part1(input) do
{ranges, ingredients} = parse(input)
Enum.count(ingredients, &in_any_range?(&1, ranges))
end
defp in_any_range?(ingredient, ranges) do
Enum.any?(ranges, &(ingredient in &1))
end
def part2(input) do
{ranges, _ingredients} = parse(input)
ranges = ranges
|> Enum.sort
|> combine_ranges
Enum.reduce(ranges, 0, &(Range.size(&1) + &2))
end
defp combine_ranges([r]), do: [r]
defp combine_ranges([r1, r2 | rest]) do
case Range.disjoint?(r1, r2) do
true ->
[r1 | combine_ranges([r2 | rest])]
false ->
r = min(r1.first, r2.first) .. max(r1.last, r2.last)
combine_ranges([r | rest])
end
end
defp parse([ranges, ingredients]) do
ranges = Enum.map(ranges, fn range ->
[first, last] = String.split(range, "-")
String.to_integer(first) .. String.to_integer(last)
end)
ingredients = Enum.map(ingredients, &String.to_integer(&1))
{ranges, ingredients}
end
end
Most Liked
hauleth
That is why I created RangeSet:
Parse
[fresh, ingridients] = String.split(puzzle_input, "\n\n")
fresh =
fresh
|> String.split()
|> Enum.map(fn range ->
[a, b] = range |> String.split("-") |> Enum.map(&String.to_integer/1)
a..b//1
end)
|> RangeSet.new()
ingridients =
ingridients
|> String.split()
|> Enum.map(&String.to_integer/1)
Part 1
Enum.count(ingridients, & &1 in fresh)
Part 2
Enum.count(fresh)
7
mudasobwa
Creator of Cure
For the first time I needed a helper private function with multiple heads to handle a recursion properly.
defmodule Day5 do
@input "day5_1.input" |> File.read!() |> String.split("\n\n", trim: true)
def calc([ranges, ids] \\ @input) do
ranges =
ranges
|> String.split(["\s", "\n"], trim: true)
|> Enum.map(&String.split(&1, "-", trim: true))
|> Enum.map(fn [b, e] -> String.to_integer(b)..String.to_integer(e)//1 end)
ids
|> String.split(["\s", "\n"], trim: true)
|> Enum.reduce({0, []}, fn id, {count, ids} ->
id = String.to_integer(id)
Enum.reduce_while(ranges, {count, ids}, fn range, {count, ids} ->
if id in range, do: {:halt, {count + 1, [id | ids]}}, else: {:cont, {count, ids}}
end)
end)
end
def in_ranges([ranges, _ids] \\ @input) do
ranges
|> String.split(["\s", "\n"], trim: true)
|> Enum.map(&String.split(&1, "-", trim: true))
|> Enum.map(fn range -> Enum.map(range, &String.to_integer/1) end)
|> Enum.sort()
|> merge([])
|> Enum.sum_by(fn [f, l] -> l - f + 1 end)
end
defp merge([], acc), do: Enum.reverse(acc)
defp merge([range | rest], []), do: merge(rest, [range])
defp merge([[f2, l2] | rest], [[f1, l1] | acc]) do
if f2 <= l1 + 1 do
merged = [f1, max(l1, l2)]
merge(rest, [merged | acc])
else
merge(rest, [[f2, l2], [f1, l1] | acc])
end
end
end
4
vkryukov
Yep, today was an easy one; parsing takes almost more lines than the rest of the code :).
defmodule Y2025.Day05 do
def fresh?(_id, []), do: false
def fresh?(id, [{a, b} | rest]) do
cond do
id < a -> false
a <= id && id <= b -> true
true -> fresh?(id, rest)
end
end
def parse(s) do
[ranges, ids] = String.split(s, "\n\n")
ranges =
ranges
|> String.split("\n")
|> Enum.map(fn line ->
[a, b] = String.split(line, "-")
{String.to_integer(a), String.to_integer(b)}
end)
|> Enum.sort() # <- important for fresh? and do_part2 to work!
ids = ids |> String.split("\n") |> Enum.map(&String.to_integer/1)
{ranges, ids}
end
def part1(s) do
{ranges, ids} = parse(s)
ids
|> Enum.filter(fn id -> fresh?(id, ranges) end)
|> length()
end
def part2(s) do
{ranges, _} = parse(s)
do_part2(ranges, 0)
end
def do_part2([], n), do: n
def do_part2([{a, b}], n), do: n + b - a + 1
def do_part2([{a, b}, {c, d} | rest], n) do
cond do
b < c -> do_part2([{c, d} | rest], n + b - a + 1)
b >= d -> do_part2([{a, b} | rest], n)
# b >= c & b < d
true -> do_part2([{a, d} | rest], n)
end
end
end
3
Last Post!
billylanchantin
For part 2, I flatten a list of range firsts and lasts and keep a running total of how many ranges overlap our place in the list.
defmodule Day05 do
def part1(file) do
{ranges, ids} = parse(file)
Enum.count(ids, fn id -> Enum.any?(ranges, &(id in &1)) end)
end
def part2(file) do
{ranges, _} = parse(file)
firsts = Enum.frequencies_by(ranges, & &1.first)
lasts = Enum.frequencies_by(ranges, &(&1.last + 1))
Enum.sort(Map.keys(firsts) ++ Map.keys(lasts))
|> Enum.scan({0, 0}, fn x, {_, c} -> {x, c + (firsts[x] || 0) - (lasts[x] || 0)} end)
|> Enum.chunk_every(2, 1, :discard)
|> Enum.sum_by(fn [{a, count}, {b, _}] -> if count > 0, do: b - a, else: 0 end)
end
def parse(file) do
[rngs, ids] = file |> File.read!() |> split("\n\n") |> Enum.map(&split(&1, "\n"))
{Enum.map(rngs, &to_rng/1), Enum.map(ids, &to_int/1)}
end
def split(str, on), do: String.split(str, on, trim: true)
def to_int(str), do: str |> Integer.parse() |> elem(0)
def to_rng(str), do: str |> split("-") |> Enum.map(&to_int/1) |> then(&apply(Range, :new, &1))
end
1
Popular in Challenges
Note: This topic is to talk about Day 18 of the Advent of Code 2019.
There is a private leaderboard for elixirforum members. You can joi...
New
This topic is about Day 5 of the Advent of Code 2020 .
Thanks to @egze, we have a private leaderboard:
https://adventofcode.com/2020/le...
New
This one has been quite the ride. Struggled at first to find a good data format to suite the problem. I really like how that turned out b...
New
Nobody’s doing Advent of Code this year? :grinning_face_with_smiling_eyes:
I might do the first week or so.
For Day 1, first I solved i...
New
The second part of today’s puzzle is very misleading.
FYI, each of the ghosts has only one possible position that ends with a "Z" on its...
New
My solution finishes both parts in 5 seconds on my computer. That time should be possible to reduce by optimizing my rather naive tilt/2 ...
New
Here is my solution for day 2 of Advent of Code:
https://github.com/bjorng/advent-of-code/blob/main/2024/day02/lib/day02.ex
New
Other popular topics
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Hi everyone!
I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
Hi All,
I set a environment variables in dev.exs , like below code.
when i start server, how can i set the ${enable} value?
thanks.
d...
New
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
New
i’m a new one to elixir
which editor can i use
vs code? or atom?
Thanks! :smiley:
New
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
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
- #api
- #forms
- #metaprogramming
- #security
- #hex









