Aetherus

Aetherus

Today’s problem is really tense. I don’t think I can do it without libgraph.

Showing Posts 1 to 10

ruslandoga

ruslandoga

Brute Enum.sort_by with String.contains?
def solve(input) do
  [rules, pages] = String.split(input, "\n\n")

  pages =
    pages
    |> String.split("\n", trim: true)
    |> Enum.map(fn line ->
      line |> String.split(",") |> Enum.map(&String.to_integer/1)
    end)

  Enum.reduce(pages, {0, 0}, fn page, {p1, p2} ->
    sorted =
      Enum.sort_by(page, &Function.identity/1, fn l, r ->
        String.contains?(rules, "#{l}|#{r}")
      end)

    mid = Enum.at(sorted, div(length(sorted), 2))

    if page == sorted do
      {p1 + mid, p2}
    else
      {p1, p2 + mid}
    end
  end)
end

Full: aoc2024/lib/day05.ex at master · ruslandoga/aoc2024 · GitHub

igorb

igorb

That’s very clever!

lud

lud

Insert sort to the rescue :slight_smile:

I took the time to check if all possible pairs were defined in the ordering rules, and indeed they are, which makes the puzzle much less hard than what it could have been :slight_smile:

defmodule AdventOfCode.Solutions.Y24.Day05 do
  alias AoC.Input

  def parse(input, _part) do
    lines = Input.read!(input) |> String.trim()
    [pairs, updates] = String.split(lines, "\n\n")

    {parse_pairs(pairs), parse_updates(updates)}
  end

  defp parse_pairs(raw) do
    raw
    |> String.split("\n")
    |> Enum.map(fn line ->
      [a, b] = String.split(line, "|")
      {String.to_integer(a), String.to_integer(b)}
    end)
  end

  defp parse_updates(raw) do
    raw
    |> String.split("\n")
    |> Enum.map(fn line ->
      line |> String.split(",") |> Enum.map(&String.to_integer/1)
    end)
  end

  def part_one({pairs, updates}) do
    updates
    |> Enum.filter(&good_update?(&1, pairs))
    |> Enum.map(&at_middle/1)
    |> Enum.sum()
  end

  defp good_update?([_last], _) do
    true
  end

  defp good_update?([left | tail], pairs) do
    Enum.all?(tail, fn right -> {left, right} in pairs end) and good_update?(tail, pairs)
  end

  defp at_middle(list) do
    Enum.at(list, div(length(list), 2))
  end

  def part_two({pairs, updates}) do
    updates
    |> Enum.filter(&(not good_update?(&1, pairs)))
    |> Enum.map(&reorder(&1, pairs))
    |> Enum.map(&at_middle/1)
    |> Enum.sum()
  end

  defp reorder(bad_list, pairs) do
    Enum.reduce(bad_list, [], fn n, ordered -> insert(ordered, n, pairs) end)
  end

  defp insert([h | t], n, pairs) do
    if {h, n} in pairs,
      do: [h | insert(t, n, pairs)],
      else: [n, h | t]
  end

  defp insert([], n, _) do
    [n]
  end
end

Edit : no need for insert sort, this would just work:

  def part_two({pairs, updates}) do
    updates
    |> Enum.filter(&(not good_update?(&1, pairs)))
    |> Enum.map(fn list -> Enum.sort(list, &({&1, &2} in pairs)) end)
    |> Enum.map(&at_middle/1)
    |> Enum.sum()
  end
code-shoily

code-shoily

I basically sorted each update (int) based on existence in a set (int*int) on (left, right) and (right, left) (used IComparable). And returned a list of tuples where left element is original update and right is sorted (is desired) update

For part 1 - sum of median of left where left = right
For part 2 - sum of median of right where left <> right

Didn’t share the code because not a beam language. It was so much fun (and fast enough) that I decided not to go topo.

lkuty

lkuty

This is the second time I am bitten by part 2. For day 2 I had to use the solution by @bjorng to find the differences between his output and mine and thus find out where I had made an incorrect assumption since my code looked 100% correct (which it was with the wrong assumption). And now part 2 again. The code looks ok but the answer is wrong :thinking: It is working with the sample data :frowning_face: I hope to fix it before day 6.

sevenseacat

sevenseacat

Author of Ash Framework

It looks like there’s a lot of different approaches today, awesome :smiley:

https://github.com/sevenseacat/advent_of_code/blob/main/lib/y2024/day05.ex

The first problem this year that I thought was too slow with my naive implementation so I added a Task.async_stream to make it faster :smiley: Now part 2 runs in 240ms which I will accept

edit: Some more optimization and I’m down to 7ms for part 2.

Name                     ips        average  deviation         median         99th %
day 05, part 1        1.01 K        0.99 ms     ±3.96%        0.98 ms        1.12 ms
day 05, part 2       0.133 K        7.52 ms     ±3.05%        7.50 ms        8.24 ms
adamu

adamu

First, I spent way too long trying to figure out a clever way to generate some kind of tree to represent the order, which I would then process everything through.

But I gave up on that and realised it can be much simpler:

  1. group_by the pairs to get a map of greater to lesser numbers
  2. Compare each pair to see if the RHS is in the map for the LHS

I also decided to implement two helper anonymous functions sorted? and greater? which are closures over the above map.

After the above preparation, each part runs in less than a ms.

def part1({updates, _greater?, sorted?}) do
  updates
  |> Enum.filter(sorted?)
  |> Enum.map(&Enum.at(&1, div(length(&1), 2)))
  |> Enum.sum()
end

def part2({updates, greater?, sorted?}) do
  updates
  |> Enum.reject(sorted?)
  |> Enum.map(&(Enum.sort(&1, greater?) |> Enum.at(div(length(&1), 2))))
  |> Enum.sum()
end

https://git.adamu.jp/adam/AdventOfCode/src/branch/main/2024/day5.exs

Where Next? Top

Trending in Challenges Top

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews