use std::collections::HashMap; fn main() { let input = include_str!("./input.txt"); let output: i32 = input.lines().map(process_line).sum(); println!("Result {}", output); } /// Return the position of `needle` in `string` fn find_ocurrences<'a>(string: &'a str, needle: &str) -> Vec<(usize, &'a str)> { string.match_indices(needle).collect() } fn find_min<'a>(matches: &[(usize, &'a str)]) -> (usize, &'a str) { let (position, word) = matches.iter().min_by(|(x,_), (y, _)| { x.cmp(y) }).unwrap(); (*position, word) } fn find_max<'a>(matches: &[(usize, &'a str)]) -> (usize, &'a str) { let (position, word) = matches.iter().min_by(|(x,_), (y, _)| { y.cmp(x) }).unwrap(); (*position, word) } /// Return the first and last number on `s` fn process_line(s: &str) -> i32 { let mapping: HashMap<&str, i32> = HashMap::from([ ("one", 1), ("two", 2), ("three", 3), ("four", 4), ("five", 5), ("six", 6), ("seven", 7), ("eight", 8), ("nine", 9), ("1", 1), ("2", 2), ("3", 3), ("4", 4), ("5", 5), ("6", 6), ("7", 7), ("8", 8), ("9", 9), ]); let matches = mapping.iter().map(|(k, _)| { find_ocurrences(s, k) }).collect::>().concat(); let (_, min_number) = find_min(&matches); let (_, max_number) = find_max(&matches); (mapping[min_number] * 10) + mapping[max_number] } #[test] fn test_find_min_1() { let input = vec!((1, "eight"), (2, "eight"), (3, "2")); assert_eq!(find_min(&input), (1, "eight")); } #[test] fn test_find_min_2() { let input = vec!((4, "eight"), (5, "eight"), (3, "2")); assert_eq!(find_min(&input), (3, "2")); } #[test] fn simple_input() { let string = "onetwo"; assert_eq!(process_line(string), 12); } #[test] fn overlap_input() { let string = "oneight"; assert_eq!(process_line(string), 18); } #[test] fn example() { let string = "two1nine eightwothree abcone2threexyz xtwone3four 4nineeightseven2 zoneight234 7pqrstsixteen"; let result: Vec = string.lines().map(process_line).collect(); assert_eq!(result, &[29, 83, 13, 24, 42, 14, 76]); }