Rust Day 1 Optimizations

This commit is contained in:
Tobias Berger 2023-12-01 22:15:51 +01:00
parent de2e672007
commit bfa1b624f8
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
2 changed files with 49 additions and 39 deletions

View file

@ -1,4 +1,4 @@
pub(crate) fn part_1(input: &'static str) -> u64 { pub(crate) fn part_1(input: &'static str) -> u32 {
input input
.lines() .lines()
.map(|line| { .map(|line| {
@ -6,9 +6,7 @@ pub(crate) fn part_1(input: &'static str) -> u64 {
let first_digit = digits.next().expect("At least 1 digit should be present"); let first_digit = digits.next().expect("At least 1 digit should be present");
let last_digit = digits.last().unwrap_or(first_digit); let last_digit = digits.last().unwrap_or(first_digit);
format!("{first_digit}{last_digit}") (((first_digit as u32) - ('0' as u32)) * 10) + ((last_digit as u32) - ('0' as u32))
.parse::<u64>()
.expect("Two digits should make a number")
}) })
.sum() .sum()
} }

View file

@ -1,52 +1,64 @@
use std::cmp::Reverse;
const DIGIT_PATTERNS: [&str; 10] = [ const DIGIT_PATTERNS: [&str; 10] = [
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
]; ];
pub(crate) fn part_2(input: &'static str) -> u64 { #[cfg_attr(test, derive(Debug))]
struct DigitIndices {
digit: usize,
first_index: usize,
last_index: usize,
}
pub(crate) fn part_2(input: &'static str) -> usize {
input input
.lines() .lines()
.map(|line| { .map(|line| {
let mut digit_indices = DIGIT_PATTERNS let digit_indices = DIGIT_PATTERNS
.iter() .iter()
.enumerate() .enumerate()
.map(|(number, pattern)| { .filter_map(|(digit, pattern)| {
let first_index_digit = line.find(&number.to_string()); // SAFETY: Generating a char from a number like this is guaranteed to be in ASCII range
let first_index_str = line.find(pattern); let first_index_digit = line
let first_index = match (first_index_str, first_index_digit) { .find(unsafe {
(Some(lhs), Some(rhs)) => Some(usize::min(lhs, rhs)), char::from_u32(digit as u32 + b'0' as u32).unwrap_unchecked()
(None, idx) => idx, })
(idx, None) => idx, .map(Reverse);
}; let first_index_str = line.find(pattern).map(Reverse);
let Reverse(first_index) = Option::max(first_index_digit, first_index_str)?;
let last_index_digit = line.rfind(&number.to_string()); // SAFETY: Generating a char from a number like this is guaranteed to be in ASCII range
let last_index_digit = line.rfind([unsafe {
char::from_u32(digit as u32 + b'0' as u32).unwrap_unchecked()
}]);
let last_index_str = line.rfind(pattern); let last_index_str = line.rfind(pattern);
let last_index = match (last_index_str, last_index_digit) { let last_index = Option::max(last_index_digit, last_index_str)?;
(Some(lhs), Some(rhs)) => Some(usize::max(lhs, rhs)),
(None, idx) => idx,
(idx, None) => idx,
};
(number, first_index, last_index) Some(DigitIndices {
digit,
first_index,
last_index,
})
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
digit_indices.sort_unstable_by(|a, b| match (a.1, b.1) { // SAFETY: Each line is guaranteed to have at least one digit
(Some(_), None) => std::cmp::Ordering::Less, let first_digit = unsafe {
(None, Some(_)) => std::cmp::Ordering::Greater, digit_indices
(None, None) => std::cmp::Ordering::Equal, .iter()
(Some(lhs), Some(rhs)) => lhs.cmp(&rhs), .min_by_key(|val| val.first_index)
}); .unwrap_unchecked()
// SAFETY: Slice is guaranteed to be length 10 }
let first_digit = unsafe { digit_indices.first().unwrap_unchecked() }.0; .digit;
digit_indices.sort_unstable_by(|a, b| match (a.2, b.2) { let last_digit = unsafe {
(Some(_), None) => std::cmp::Ordering::Less, digit_indices
(None, Some(_)) => std::cmp::Ordering::Greater, .iter()
(None, None) => std::cmp::Ordering::Equal, .max_by_key(|val| val.last_index)
(Some(lhs), Some(rhs)) => rhs.cmp(&lhs), .unwrap_unchecked()
}); }
let last_digit = unsafe { digit_indices.first().unwrap_unchecked() }.0; .digit;
format!("{first_digit}{last_digit}")
.parse::<u64>() (first_digit * 10) + last_digit
.expect("digits are guaranteed to create a valid number")
}) })
.sum() .sum()
} }