Aetherus
Advent of Code 2020 - Day 1
Finished Day 1 with Elixir 
Here’s my code:
#!/usr/bin/env elixir
defmodule Combination do
@doc "Yields each combination of 2"
def c2(list, _fun) when length(list) < 2, do: :ok
def c2([a|tail], fun) do
Enum.each(tail, fn(b)-> fun.(a, b) end)
c2(tail, fun)
end
@doc "Yields each combination of 3"
def c3(list, _fun) when length(list) < 3, do: :ok
def c3([a|tail], fun) do
c2(tail, fn(b, c)-> fun.(a, b, c) end)
c3(tail, fun)
end
end
nums = "./day1.txt"
|> File.stream!([], :line)
|> Stream.map(&String.trim/1)
|> Enum.map(&String.to_integer/1)
Combination.c2(nums, fn(a, b)->
if a + b == 2020 do
IO.inspect(a * b, label: "Part 1")
end
end)
Combination.c3(nums, fn(a, b, c)->
if a + b + c == 2020 do
IO.inspect(a * b * c, label: "Part 2")
end
end)
Most Liked
adamu
Here’s mine for Day 1. It’s my second implementation, after I realised during part 2 that comprehensions made the whole thing much simpler.
list =
File.read!("input")
|> String.trim()
|> String.split("\n")
|> Enum.map(&String.to_integer/1)
[{a, b} | _] = for i <- list, j <- list, i + j == 2020, do: {i, j}
IO.puts("Part1: #{a} x #{b} = #{a * b}")
[{a, b, c} | _] = for i <- list, j <- list, k <- list, i + j + k == 2020, do: {i, j, k}
IO.puts("Part2: #{a} x #{b} x #{c} = #{a * b * c}")
I’m putting my solutions on Github.
LostKobrakai
Part 1 can be optimized by spliting the list in half between greater 1010 and smaller and only searching for a pairs of one number in each. There cannot be two numbers smaller or two numbers greater than 1010 to add up to 2020.
Edit: I’ve added some benchmarks.
mexicat
My solution:
defmodule AdventOfCode.Day01 do
def part1(input) do
{a, b} =
input
|> String.trim()
|> String.split("\n")
|> Enum.map(&String.to_integer/1)
|> find_two_entries_that_sum_to_2020()
a * b
end
def part2(input) do
{a, b, c} =
input
|> String.trim()
|> String.split("\n")
|> Enum.map(&String.to_integer/1)
|> find_three_entries_that_sum_to_2020()
a * b * c
end
def find_two_entries_that_sum_to_2020(entries) do
Enum.reduce_while(entries, nil, fn entry, _acc ->
n_to_find = 2020 - entry
case Enum.find(entries, fn x -> x == n_to_find end) do
nil -> {:cont, nil}
x -> {:halt, {entry, x}}
end
end)
end
def find_three_entries_that_sum_to_2020(entries) do
try do
for a <- entries,
b <- entries,
c <- entries,
a + b + c == 2020,
# exit as soon as we find the solution
do: throw({:break, {a, b, c}})
catch
{:break, result} -> result
end
end
end
After finishing part 1 I realized that my approach would not work with part 2, so they’re quite different 
I tried to make both parts efficient, so they stop calculation as soon as they find a correct result.
egze
Did it with streams:
defmodule Aoc.Y2020.D1 do
use Aoc.Boilerplate,
transform: fn raw -> raw |> String.split() |> Enum.map(&String.to_integer(&1)) end
def part1(input \\ processed()) do
[{x, y}] =
Stream.flat_map(input, fn i ->
Stream.flat_map(input, fn j ->
[{i, j}]
end)
end)
|> Stream.filter(fn {x, y} ->
x + y == 2020
end)
|> Enum.take(1)
x * y
end
def part2(input \\ processed()) do
[{x, y, z}] =
Stream.flat_map(input, fn i ->
Stream.flat_map(input, fn j ->
Stream.flat_map(input, fn k ->
[{i, j, k}]
end)
end)
end)
|> Stream.filter(fn {x, y, k} ->
x + y + k == 2020
end)
|> Enum.take(1)
x * y * z
end
end
hauleth
My solution which uses the fact that searching for a + b + c == 2020 is the same as searching for b + c == 2020 - a and the fact that a + b == b + a and a * b == b * a, which mean that [a, …, b] will return the same result as [b, …, a] (in other words, if we didn’t found the solution for earlier elements in list, we never need to look at them anymore):
defmodule Solution do
def read_input(path) do
path
|> File.stream!()
|> Stream.map(&String.to_integer(String.trim(&1)))
|> Enum.to_list()
end
def run([], _, _), do: nil
def run(_, _, sum) when sum < 0, do: nil
def run([a | _], 1, a), do: [a]
def run([a | rest], n, sum) do
case run(rest, n - 1, sum - a) do
nil -> run(rest, n, sum)
nums when is_list(nums) -> [a | nums]
end
end
end
list = Solution.read_input("input.txt")
list
|> Solution.run(2, 2020)
|> Enum.reduce(&*/2)
|> IO.inspect(label: "task 1")
list
|> Solution.run(3, 2020)
|> Enum.reduce(&*/2)
|> IO.inspect(label: "task 2")
Oh, this is also generic solution for any amount of elements that need to sum to given value.
I have benched against @LostKobrakai code and this is result:
Operating System: macOS
CPU Information: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
Number of Available Cores: 8
Available memory: 32 GB
Elixir 1.11.2
Erlang 22.3
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 21 s
Benchmarking first solution...
Benchmarking mine...
Benchmarking optimized...
Name ips average deviation median 99th %
mine 3.92 K 254.84 μs ±7.99% 251.98 μs 348.98 μs
optimized 3.68 K 271.99 μs ±10.21% 266.98 μs 397.98 μs
first solution 0.0200 K 49956.44 μs ±12.46% 48000.98 μs 70571.10 μs
Comparison:
mine 3.92 K
optimized 3.68 K - 1.07x slower +17.15 μs
first solution 0.0200 K - 196.03x slower +49701.60 μs







