Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 5

day5.livemd

Day 5

Mix.install(
  [
    {:benchee, "~> 1.3"}
  ]
)

Setup

input =
  System.fetch_env!("LB_AOC_DIR")
  |> Path.join("data/day5.txt")
  |> File.read!()

nil
nil

Solve

defmodule Day5 do
  defp parse(input) do
    [instructions, pages] = String.split(input, "\n\n")

    instructions =
      for instruction <- String.split(instructions, "\n") do
        for i <- String.split(instruction, "|") do
          String.to_integer(i)
        end
      end
      |> MapSet.new()

    pages =
      for page <- String.split(pages, "\n"), page != "" do
        for number <- String.split(page, ",") do
          String.to_integer(number)
        end
      end

    {instructions, pages}
  end

  @doc ~S"""
  iex> Day5.part1("47|53\n97|13\n97|61\n97|47\n75|29\n61|13\n75|53\n29|13\n97|29\n53|29\n61|53\n97|53\n61|29\n47|13\n75|47\n97|75\n47|61\n75|61\n47|29\n75|13\n53|13\n\n75,47,61,53,29\n97,61,53,29,13\n75,29,13\n75,97,47,61,53\n61,13,29\n97,13,75,29,47\n")
  143
  """
  def part1(input) do
    {instructions, pages} = parse(input)

    for page <- pages, reduce: 0 do
      sum ->
        reordered = Enum.sort(page, &amp;MapSet.member?(instructions, [&amp;1, &amp;2]))

        if reordered == page do
          middle = floor(length(page) / 2)
          sum + Enum.at(page, middle)
        else
          sum
        end
    end
  end

  @doc ~S"""
  iex> Day5.part2("47|53\n97|13\n97|61\n97|47\n75|29\n61|13\n75|53\n29|13\n97|29\n53|29\n61|53\n97|53\n61|29\n47|13\n75|47\n97|75\n47|61\n75|61\n47|29\n75|13\n53|13\n\n75,47,61,53,29\n97,61,53,29,13\n75,29,13\n75,97,47,61,53\n61,13,29\n97,13,75,29,47\n")
  123
  """
  def part2(input) do
    {instructions, pages} = parse(input)

    for page <- pages, reduce: 0 do
      sum ->
        reordered = Enum.sort(page, &amp;MapSet.member?(instructions, [&amp;1, &amp;2]))

        if reordered == page do
          sum
        else
          middle = floor(length(reordered) / 2)
          sum + Enum.at(reordered, middle)
        end
    end
  end

  def bench(input) do
    Benchee.run(
      %{
        "part1" => fn -> part1(input) end,
        "part2" => fn -> part2(input) end
      },
      time: 10,
      memory_time: 2
    )
  end
end
{:module, Day5, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:bench, 1}}
Day5.bench(input)
Error trying to determine erlang version enoent, falling back to overall OTP version
Operating System: macOS
CPU Information: Apple M1 Max
Number of Available Cores: 10
Available memory: 32 GB
Elixir 1.17.2
Erlang 27
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 10 s
memory time: 2 s
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 28 s

Benchmarking part1 ...
Benchmarking part2 ...
Calculating statistics...
Formatting results...

Name            ips        average  deviation         median         99th %
part1        1.05 K      951.94 μs    ±11.95%      928.92 μs     1141.02 μs
part2        1.05 K      955.29 μs    ±18.72%      929.38 μs     1134.73 μs

Comparison: 
part1        1.05 K
part2        1.05 K - 1.00x slower +3.36 μs

Memory usage statistics:

Name          average  deviation         median         99th %
part1       722.37 KB     ±0.00%      722.37 KB      722.41 KB
part2       722.61 KB     ±0.00%      722.60 KB      722.65 KB

Comparison: 
part1       722.37 KB
part2       722.61 KB - 1.00x memory usage +0.23 KB
%Benchee.Suite{
  system: %Benchee.System{
    elixir: "1.17.2",
    erlang: "27",
    jit_enabled?: true,
    num_cores: 10,
    os: :macOS,
    available_memory: "32 GB",
    cpu_speed: "Apple M1 Max"
  },
  configuration: %Benchee.Configuration{
    parallel: 1,
    time: 10000000000.0,
    warmup: 2000000000.0,
    memory_time: 2000000000.0,
    reduction_time: 0.0,
    pre_check: false,
    formatters: [Benchee.Formatters.Console],
    percentiles: ~c"2c",
    print: %{configuration: true, benchmarking: true, fast_warning: true},
    inputs: nil,
    input_names: [],
    save: false,
    load: false,
    unit_scaling: :best,
    assigns: %{},
    before_each: nil,
    after_each: nil,
    before_scenario: nil,
    after_scenario: nil,
    measure_function_call_overhead: false,
    title: nil,
    profile_after: false
  },
  scenarios: [
    %Benchee.Scenario{
      name: "part1",
      job_name: "part1",
      function: #Function<0.96581357/0 in Day5.bench/1>,
      input_name: :__no_input,
      input: :__no_input,
      before_each: nil,
      after_each: nil,
      before_scenario: nil,
      after_scenario: nil,
      tag: nil,
      run_time_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 951935.9977145034,
          ips: 1050.4907918188756,
          std_dev: 113779.55023414688,
          std_dev_ratio: 0.11952436981826449,
          std_dev_ips: 125.55924989204077,
          median: 928923.0,
          percentiles: %{50 => 928923.0, 99 => 1141021.6599999995},
          mode: 914257,
          minimum: 869340,
          maximum: 5411247,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 10501
        },
        samples: [1056758, 955257, 991423, 938757, 1022799, 955215, 936090, 968090, 937632, 954091,
         916382, 915506, 913382, 911590, 978590, 1088508, 1003257, 925799, 972340, 929174, 1007174,
         940965, 1184925, 997842, 1134841, 1063758, 1045507, 959965, 1031091, 1074592, 1420844,
         964007, 1030092, ...]
      },
      memory_usage_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 739707.9061032864,
          ips: nil,
          std_dev: 13.127269633597354,
          std_dev_ratio: 1.774655850679035e-5,
          std_dev_ips: nil,
          median: 739704.0,
          percentiles: %{50 => 739704.0, 99 => 739752.0},
          mode: 739704,
          minimum: 739704,
          maximum: 739752,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 1917
        },
        samples: [739704, 739704, 739704, 739704, 739704, 739704, 739704, 739704, 739704, 739704,
         739704, 739752, 739704, 739704, 739752, 739704, 739704, 739704, 739704, 739704, 739752,
         739704, 739704, 739704, 739752, 739704, 739704, 739704, 739704, 739704, 739752, 739704,
         ...]
      },
      reductions_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: nil,
          ips: nil,
          std_dev: nil,
          std_dev_ratio: nil,
          std_dev_ips: nil,
          median: nil,
          percentiles: nil,
          mode: nil,
          minimum: nil,
          maximum: nil,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 0
        },
        samples: []
      }
    },
    %Benchee.Scenario{
      name: "part2",
      job_name: "part2",
      function: #Function<1.96581357/0 in Day5.bench/1>,
      input_name: :__no_input,
      input: :__no_input,
      before_each: nil,
      after_each: nil,
      before_scenario: nil,
      after_scenario: nil,
      tag: nil,
      run_time_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 955294.3271858576,
          ips: 1046.7977999469945,
          std_dev: 178817.49346367034,
          std_dev_ratio: 0.18718575874980617,
          std_dev_ips: 195.94564044070597,
          median: 929382.0,
          percentiles: %{50 => 929382.0, 99 => 1134730.78},
          mode: 897048,
          minimum: 871006,
          maximum: 9666529,
          relative_more: 1.0035278941855514,
          relative_less: 0.9964845080978894,
          absolute_difference: 3358.32947135414,
          sample_size: 10465
        },
        samples: [1070466, 935548, 1003007, 973548, 970465, 971257, 976090, 998175, 942673, 967799,
         919132, 912632, 921173, 920966, 985215, 942549, 964632, 947716, 903215, 927214, 911132,
         989924, 942090, 954132, 931757, 915174, 911923, 954882, 983716, 945715, 956424, 915965,
         ...]
      },
      memory_usage_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 739947.9979434448,
          ips: nil,
          std_dev: 13.266809195171335,
          std_dev_ratio: 1.7929380486255923e-5,
          std_dev_ips: nil,
          median: 739944.0,
          percentiles: %{50 => 739944.0, 99 => 739992.0},
          mode: 739944,
          minimum: 739944,
          maximum: 739992,
          relative_more: 1.0003245765499833,
          relative_less: 0.9996755287657705,
          absolute_difference: 240.09184015833307,
          sample_size: 1945
        },
        samples: [739944, 739944, 739944, 739944, 739944, 739944, 739944, 739944, 739944, 739944,
         739944, 739992, 739992, 739944, 739944, 739944, 739944, 739992, 739944, 739944, 739992,
         739944, 739944, 739944, 739944, 739944, 739944, 739944, 739944, 739944, 739944, ...]
      },
      reductions_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: nil,
          ips: nil,
          std_dev: nil,
          std_dev_ratio: nil,
          std_dev_ips: nil,
          median: nil,
          percentiles: nil,
          mode: nil,
          minimum: nil,
          maximum: nil,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 0
        },
        samples: []
      }
    }
  ]
}