bjorng

bjorng

Erlang Core Team

Advent of Code 2024 - Day 1

Here is my solution for day 1 of Advent of Code:

defmodule Day01 do
  def part1(input) do
    all = parse(input)
    {first, second} = Enum.unzip(all)
    Enum.zip([Enum.sort(first), Enum.sort(second)])
    |> Enum.map(fn {a, b} ->
      abs(a - b)
    end)
    |> Enum.sum
  end

  def part2(input) do
    all = parse(input)
    {first, second} = Enum.unzip(all)
    frequencies = Enum.frequencies(second)
    first
    |> Enum.map(fn n ->
      n * Map.get(frequencies, n, 0)
    end)
    |> Enum.sum
  end

  defp parse(input) do
    input
    |> Enum.map(fn line ->
      {first, line} = Integer.parse(line)
      line = String.trim(line)
      {second, ""} = Integer.parse(line)
      {first, second}
    end)
  end
end

Most Liked

al2o3cr

al2o3cr

I liked this solution for part 1 because of the unzip / process / zip pattern:

File.stream!("example.txt")
|> Stream.map(&String.trim/1)
|> Stream.map(&String.split/1)
|> Stream.map(fn [a, b] -> {String.to_integer(a), String.to_integer(b)} end)
|> Enum.unzip()
|> then(fn {l, r} -> [Enum.sort(l), Enum.sort(r)] end)
|> Stream.zip()
|> Stream.map(fn {a, b} -> abs(b-a) end)
|> Enum.sum()
|> IO.inspect()

Part 2 wasn’t quite as symmetrical:

{left, right} =
  File.stream!("input.txt")
  |> Stream.map(&String.trim/1)
  |> Stream.map(&String.split/1)
  |> Stream.map(fn [a, b] -> {String.to_integer(a), String.to_integer(b)} end)
  |> Enum.unzip()

f_right = Enum.frequencies(right)

left
|> Stream.map(fn l -> {l, Map.get(f_right, l, 0)} end)
|> Stream.map(fn {l, n} -> l * n end)
|> Enum.sum()
|> IO.inspect()

Technically it would be faster to fuse successive Stream.maps into a single one with a more-complicated function, but writing in this style keeps each line focused on a specific transformation.

clayscode

clayscode

Signed up just to say thank you for this comment! Didn’t know about the then function. Subsequently have learned about the tap function as well thanks to this article: Useful Elixir Functions You May Not Know: tap() & then()

I guess it’s not that different from |> fn x -> x end.(), but it at least feels a bit nicer.

dimitarvp

dimitarvp

I got so severely humbled by @billylanchantin that I just copied his code with very slight changes like adding types and specs and doctests, and extracting functions for better understanding of what does what, plus have common AOC helpers in a separate module.

In my defense for stealing his code, I did stare at the code for 40 minutes and played with it in iex until I understood exactly how it’s working. And then I was finally like “gods, I would absolutely do it this way if I knew about this Elixir API!”.

But yeah, I had no idea about Enum.zip_with and Enum.zip_reduce. Lesson learned – check Elixir’s CHANGELOGs!

Here’s my final Day 1 version:

https://github.com/dimitarvp/advent-of-code-2024-elixir/blob/main/lib/day01.ex

Where Next?

Popular in Challenges Top

maennchen
Ok, that was a rough one today. I haven’t found a way to improve the algorithm further. Part 1 runs in .5 seconds, Part 2 in ~ 5 minutes...
New
woolfred
It is that time of the year again: Advent of Code 2022 :christmas_tree: Day 1 Leaderboard:
New
sasajuric
Note: This topic is to talk about Day 12 of the Advent of Code. For general discussion about the Advent of Code 2018 and links to topics...
New
kwando
Phew, this one took a while to get right. My naive attempts was way to slow so I reached for Dijkstras shortest path algorithm.. and that...
New
ehayun
I have 2 arrays: a1 can be any combination of value or nil like that a1 = [1,nil,3] and array 2 the same a2 = [4,2, nil] How do I com...
New
Aetherus
This topic is about Day 15 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/l...
New
adamu
Probably not the most efficient implementation, because part 1 took >1 ms and part 2 >4ms, but the code was simple enough. def p...
New
rvnash
Anyone have a solution to Part 2 today? Part 1 was straight forward, but I can’t figure out a programatic way to do part 2. I understand ...
New
Aetherus
Don’t know why the regex ~r/[\W && [^\.]]/x does not work in Elixir. It works pretty well in Ruby. Anyway, here is my solution: ...
New
bjorng
Note: This topic is to talk about Day 13 of the Advent of Code 2019. There is a private leaderboard for elixirforum members. You can joi...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42920 311
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
vonH
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
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement