Advent of Code - Day 1
Day One - Part A
The first problem was determining how many times a value was larger than the preceding value.
I know Elixir
has a fantastic core library called Enum
, but I like using recursion to see what is happening. The first thing was to have a look at the data.
Below is a subset of a list of depths.
[ 171, 173, 174, 163, 161 ...]
I always like to start with my exit function when writing recursive functions. I know I will match on an empty list, so I start there. I also know I want the result, so I return it.
def count_increasing_depths([], count), do: count
Next is the main logic. I need to assess each record and then update the count.
def count_increasing_depths([h | t], count) do
count = ...
count_increasing_depths(t, count)
end
The logic is if the current value of h
is larger than the last value, then add 1 to the count. To make this work, I need to pass the value of the previous call. Adjusting my function signatures, I get the following and can now implement my test.
def count_increasing_depths([], count, _last), do: count
def count_increasing_depths([h | t], count, last) do
count = if last < h, do: count + 1, else: count
count_increasing_depths(t, count, h)
end
To run the code, I call it with the starting values Advant.count_increasing_depths(depths(), 0, 0)
. This works nicely but does not give me the correct answer. After re-reading the question, I realise I need to account for the first value not being assessed. To fix this, I need another match on the function.
def count_increasing_depths([h | t], count, 0), do: count_increasing_depths(t, count, h)
def count_increasing_depths([], count, _last), do: count
def count_increasing_depths([h | t], count, last) do
count = if last < h, do: count + 1, else: count
count_increasing_depths(t, count, h)
end
Now when I run Advant.count_increasing_depths(depths(), 0, 0)
the first match extracts the first value and starts the recursive call. The answer is correct, so Happy Days.
Day One - Part B
The second part of the problem is a little more complex, and it requires adding a sliding window of values and then making the same comparison. Since I already have a function that counts the increasing values, I decided to build a new list that can be passed into count_increasing_depths/3
; I started with my exit.
def sum_sliding_window([], results), do: results
Now I needed a function to do the test. I know I needed the first three values, so I started there. I match the first three values and add them together. I then add that to an accumulator called results
by adding them to the start of the list [ sum | results]
.
def sum_sliding_window([a, b, c | t], results) do
sum = a + b + c
sum_sliding_window(t, [sum | results])
end
The problem is that the t
is missing two of the values I need in the next iteration. The simplest solution is to put them back.
def sum_sliding_window([], results), do: results
def sum_sliding_window([a, b, c | t], results) do
sum = a + b + c
tail = [b, c | t]
sum_sliding_window(tail, [sum | results])
end
Now I can run the code Advant.sum_sliding_window(depths(), []) |> Advant.count_increasing_depths(0, 0)
but no dice the answer is wrong. This took me a minute to figure out, and I had to get some smaller test data to see what I was doing wrong. In the end, it was a silly mistake; when I created the new list with [ sum | results]
, I was reversing the order of the values. I made a quick adjustment to my exit function, and happy days again!
def sum_sliding_window([], results), do: Enum.reverse(results)
def sum_sliding_window([a, b, c | t], results) do
sum = a + b + c
tail = [b, c | t]
sum_sliding_window(tail, [sum | results])
end