use std::ops::RangeInclusive; pub fn day5_part1(input: &str) -> String { let (ranges, ingredients) = parse(input); ingredients .into_iter() .filter(|ingredient| ranges.iter().any(|range| range.contains(ingredient))) .count() .to_string() } pub fn day5_part2(input: &str) -> String { let (mut ranges, _) = parse(input); ranges.sort_by_key(|r| *r.start()); collapse(&ranges) .into_iter() .map(|range| range.end() - range.start() + 1) .sum::() .to_string() } /// ranges must be sorted fn collapse(ranges: &[RangeInclusive]) -> Vec> { let mut collapsed = vec![]; let mut current_range = ranges[0].clone(); for range in ranges { if range.start() <= current_range.end() { if range.end() > current_range.end() { current_range = *current_range.start()..=*range.end() } } else { collapsed.push(current_range); current_range = range.clone(); } } collapsed.push(current_range); collapsed } fn parse(input: &str) -> (Vec>, Vec) { let (ranges, ingredients) = input.split_once("\n\n").unwrap(); let ranges = ranges .lines() .map(|line| line.split_once('-').unwrap()) .map(|(l, r)| l.parse().unwrap()..=r.parse().unwrap()) .collect(); let ingredients = ingredients .lines() .map(|line| line.parse().unwrap()) .collect(); (ranges, ingredients) }