To be honest, for a simple, one-off problem, I disagree that hardcoding an input file name is disadvantageous. Similarly for error handling; you know the file is there and will read fine, so unwrap
ping it is fine; if it fails for some stupid reason there's no recovery you can do anyway.
And because the problem is so simple, there's not much to go about complaining about. This is a perfectly fine solution, because it's very readable.
But there are a few places where the standard library could be better utilized: (Note: I may go a little far here. Go as far iterator as you feel comfortable.)
The iteration over content
's indices in get_input
can be replaced by a mutating iterator:
for byte in &mut content {
*byte -= b'0';
}
Here I've also used a byte character literal, rather than casting to u8
, which clippy will warn you about. With a known constant, it's safe, but then you should just use the byte literal.
What this says is to, for each position in content
, take the thing at the position *byte
, and decrement (-=
) it by b'0'
. It's the exact same as what you did, except without the manual indexing. (It's probably lowered to the same machine code in the end, but iterators are fun!)
offset_sum
provides a more interesting field for refactoring, though. It can be done in one iterator chain by cleverly utilizing the available tools.
input
Start with the slice,
.iter()
and get an iterator from it.
.cloned()
Since we're operating over a Copy
type, I dereference it here for convenience. If we just call iter
, we get an iterator over &u8
, but calling cloned
clone
s each element, which in this case is just a cheap Copy
. Don't go doing this with non-copy types, though; this is just a convenience.
.enumerate()
We pair up each byte with its index in the iterator.
.filter(|&(i, b)| b == input[(i + offset) % input.len()])
Filter out all of the numbers that don't match our requirements.
.map(|(_, b)| u32::from(b))
Map our iterator back to just the number we care about. Convert it to a u32
so that we can
.sum()
it into a u32
and consume the iterator.
Try it Online!
Some fun extensions you might try:
This is always going to be an \$O(n)\$ algorithm because you have to scan the whole string. But rather than handle indices, in the first half you could use windows
to grab each neighboring pair of bytes, though you will have to handle wraparound somehow. In the second half, you can reduce the number of comparisons you have to do by half, because each number is compared against the same number in either direction (the absolute opposite of a circular buffer). Maybe you can split
the slice into two halves, then zip
the two halves together for comparisons?