Advent of Code 2024 day 1, part 2
This is a short update to my previous post where I will solve the second part. At the end, I will also include one-line solutions to the two problems, which really doesn't involve more than removal of unnecessary variable assignments.
Revisiting part 1, here's the full solution that was written in that post (with a few less variable reassignments):
numbers ← ⍎¨ ⊃ {(@\s≠⍵) ⊂ ⍵}¨ io:read "part01.txt"
(a b) ← ⊂[0] numbers
a ← ∧a
b ← ∧b
+/ | a - b
Solution to part 2
Let's keep the first two lines from the solution to part 1. Here we have the two arrays in a
and b
.
The problem statement explains that for each number in the left column (array a
), we want to multiply that value with the number of times that number occurs in the right column (array b
).
This begs the question: How do we count the number of occurrences of a value in an array?
Let's say we have the following array: 1 2 10 2 2 1 5
, and we want to count the number of 2
's.
We take advantage of the fact that the values for false and true in Kap is 0
and 1
respectively. So all we need to do is to compare the array with the value we're looking for:
2 = 1 2 10 2 2 1 5
┌→────────────┐
│0 1 0 1 1 0 0│
└─────────────┘
And then we can take the sum of the result:
+/ 2 = 1 2 10 2 2 1 5
3
We can now write a function that takes the value to search for on the left, and the full array of values to search for on the right:
{⍺ × +/⍺=⍵}
Since the left and right arguments are called ⍺
and ⍵
respectively, this multiplies the left argument with the number of occurrences of that value in the right argument.
All we have to do now is to call this function once for each value in a
, passing in the entire argument b
to the function, and then sum the result:
+/ a {⍺×+/⍺=⍵}¨ ⊂b
We use ⊂
to enclose the array b
into a scalar in order to ensure that the entire array is passed to each invocation, instead of mapping over all elements in the array.
The final code looks like this:
numbers ← ⍎¨ ⊃ {(@\s≠⍵) ⊂ ⍵}¨ io:read "part01.txt"
(a b) ← ⊂[0] numbers
+/ a {⍺×+/⍺=⍵}¨ ⊂b
One-line solutions
One-line solution to part 1
We can make the code a bit less verbose by not breaking out the two arrays into variables and instead keep it as a 2-element list. And once we did that, there is no need for the variable numbers
, which turns the solution into a single line:
+/ | ⊃-/ ∧¨ ⊂[0] ⍎¨ ⊃ {(@\s≠⍵) ⊂ ⍵}¨ io:read "part01.txt"
One-line solution to part 2
There are shorter solutions to this that I was considering including here, but they take advantage of more advanced concepts, so instead I show this solution, which should be understandable without knowing how compositional operators work.
We're simply creating an outer function to automatically bind the two arrays as function arguments instead of explicit variable assignment.
{ +/ ⍺ {⍺×+/⍺=⍵}¨ ⊂⍵ }/ ⊂[0] ⍎¨ ⊃ {(@\s≠⍵) ⊂ ⍵}¨ io:read "part01.txt"