Day 1 - Pair and sum boys, pair and sum
Created on Sunday, December 1, 2024.
Day 1
Ok, we have to take a list of pairs of numbers, split them apart, sort them, and then pair them again to calculate the differences.
Our generator will handle taking each line and generating a tuple of two numbers.
let numpair = line.split_whitespace().collect::<Vec<&str>>();
if numpair.len() == 2 {
return (
i32::from_str(numpair[0]).expect("Should be a digit"),
i32::from_str(numpair[1]).expect("Should be a digit"),
);
}
Because we want to sort the lists, we're going to inefficiently use two iterators, one taking all the first of the pair, and one taking all of the second of the pair. We'll push those into a vector, sort it, and then we can zip them up with an iterator over the pair, finding the absolute difference between them.
Ok, parsing integers from strings is a bit of faff. In this case we know we have good inputs, so I've used expect to handle the Try. That consumes an OK and panics on an Err. A better thing here would be to have a match that handles the error appropriately, but in this case, panicking is probably the right move.
Ok, so lets do part 1. We're going to iterate over the list of numbers, pushing each item into a pair of vectors, and then we'll sort the vectors, and then zip them and total up the differences.
This give us this
for pair in input {
left.push(pair.0);
right.push(pair.1);
}
left.sort();
right.sort();
let mut total = 0;
for pair in left.iter().zip(right) {
total += if *pair.0 > pair.1 {
pair.0 - pair.1
} else {
pair.1 - pair.0
}
}
But anytime we see a for loop that is adding stuff up, we can almost certainly do it more cleanly using the more functional map approach, like so:
left.iter()
.zip(right)
.map(|pair| (pair.0 - pair.1).abs())
.sum()
This zips the left and right sequences together, and for each pair, it takes the absolute value of subtracting left from right, and then it simply adds them all together.
Done, and onto part 2.
Part 2
This time we're counting the number of occorences in the right list instead of multiplying directly.
We can use a counter to count the right side, and then we can map the left list by multiplying it by the counts on the right.
Using what we learned from last time, we know we want to manage a mapping of whether we've seen the number of thigns on the left side. A Counter is a form of set from key to value, that assumes we want counts as the values.
let mut counter: Counter<i32, i32> = Counter::new();
input.iter().for_each(|pair| counter[&pair.1] += 1);
input
.iter()
.map(|pair| counter.get(&pair.0).unwrap_or(&0) * pair.0)
.sum()
We have to use for_each
for the first result, rather than map
, because we're after the side effect rather than the result. We don't care what the counter[&pair.1] += 1
return value is, just that it happens.
That works trivially, and onto day 2!
Next
Day 2 - 99 green bottles sitting on a wall
Previous