|
1 |
| -use std::collections::HashMap; |
| 1 | +use std::collections::{HashMap, HashSet}; |
2 | 2 | use std::fs;
|
3 | 3 | use std::hash::Hash;
|
4 | 4 |
|
@@ -43,32 +43,33 @@ fn is_safe_part1(report: &Vec<i32>) -> bool {
|
43 | 43 | .all(|x| x < 4);
|
44 | 44 |
|
45 | 45 | let is_strictly_monotonic = 1
|
46 |
| - == unique( |
47 |
| - report |
48 |
| - .windows(2) |
49 |
| - .map(|pair| { |
50 |
| - let [a, b] = pair else { unreachable!() }; |
51 |
| - i32::signum(a - b) |
52 |
| - }) |
53 |
| - .collect(), |
54 |
| - ) |
55 |
| - .len(); |
56 |
| - steps_small_enough && is_strictly_monotonic |
57 |
| -} |
| 46 | + == report |
| 47 | + .windows(2) |
| 48 | + .map(|pair| { |
| 49 | + let [a, b] = pair else { unreachable!() }; |
| 50 | + i32::signum(a - b) |
| 51 | + }) |
| 52 | + .uniques() |
| 53 | + .count(); |
| 54 | + // instead of |
| 55 | + // let is_strictly_monotonic = 1 |
| 56 | + // == unique( |
| 57 | + // report |
| 58 | + // .windows(2) |
| 59 | + // .map(|pair| { |
| 60 | + // let [a, b] = pair else { unreachable!() }; |
| 61 | + // i32::signum(a - b) |
| 62 | + // }) |
| 63 | + // .collect(), |
| 64 | + // ) |
| 65 | + // .len(); |
58 | 66 |
|
59 |
| -fn unique<T>(v: Vec<T>) -> Vec<T> |
60 |
| -where |
61 |
| - T: Eq + Hash, |
62 |
| -{ |
63 |
| - v.into_iter() |
64 |
| - .collect::<std::collections::HashSet<T>>() |
65 |
| - .into_iter() |
66 |
| - .collect() |
| 67 | + steps_small_enough && is_strictly_monotonic |
67 | 68 | }
|
68 | 69 |
|
69 | 70 | fn is_safe_part2(mut report: Vec<i32>) -> bool {
|
70 |
| - if is_safe_part2_(report.clone()){ |
71 |
| - return true; |
| 71 | + if is_safe_part2_(report.clone()) { |
| 72 | + return true; |
72 | 73 | }
|
73 | 74 | report.reverse();
|
74 | 75 | is_safe_part2_(report)
|
@@ -124,3 +125,95 @@ where
|
124 | 125 | condition(a, b)
|
125 | 126 | })
|
126 | 127 | }
|
| 128 | + |
| 129 | +#[allow(dead_code)] |
| 130 | +fn unique<T>(v: Vec<T>) -> Vec<T> |
| 131 | +where |
| 132 | + T: Eq + Hash, |
| 133 | +{ |
| 134 | + v.into_iter() |
| 135 | + .collect::<std::collections::HashSet<T>>() |
| 136 | + .into_iter() |
| 137 | + .collect() |
| 138 | +} |
| 139 | + |
| 140 | + |
| 141 | +// upside: can be chained nicely, is lazy |
| 142 | +// downside: need clonable, up to 2x memory requirements |
| 143 | +struct Uniques<I, T> |
| 144 | +where |
| 145 | + T: Eq + Hash + Clone, |
| 146 | + I: Iterator<Item = T>, |
| 147 | +{ |
| 148 | + input: I, |
| 149 | + seen: HashSet<T>, |
| 150 | +} |
| 151 | + |
| 152 | +impl<I, T> Uniques<I, T> |
| 153 | +where |
| 154 | + T: Eq + Hash + Clone, |
| 155 | + I: Iterator<Item = T>, |
| 156 | +{ |
| 157 | + fn new(input: I) -> Self { |
| 158 | + Self { |
| 159 | + input, |
| 160 | + seen: HashSet::new(), |
| 161 | + } |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +impl<I, T> Iterator for Uniques<I, T> |
| 166 | +where |
| 167 | + T: Eq + Hash + Clone, |
| 168 | + I: Iterator<Item = T>, |
| 169 | +{ |
| 170 | + type Item = T; |
| 171 | + |
| 172 | + fn next(&mut self) -> Option<Self::Item> { |
| 173 | + while let Some(item) = self.input.next() { |
| 174 | + if self.seen.insert(item.clone()) { |
| 175 | + return Some(item); |
| 176 | + } |
| 177 | + } |
| 178 | + None |
| 179 | + } |
| 180 | +} |
| 181 | + |
| 182 | +// Extension trait to make it convenient to use |
| 183 | +trait IteratorExt: Iterator { |
| 184 | + fn uniques(self) -> Uniques<Self, Self::Item> |
| 185 | + where |
| 186 | + Self: Sized, |
| 187 | + Self::Item: Eq + Hash + Clone, |
| 188 | + { |
| 189 | + Uniques::new(self) |
| 190 | + } |
| 191 | +} |
| 192 | + |
| 193 | +impl<I: Iterator> IteratorExt for I {} |
| 194 | + |
| 195 | +#[cfg(test)] |
| 196 | +mod tests { |
| 197 | + use super::*; |
| 198 | + |
| 199 | + #[test] |
| 200 | + fn test_uniques() { |
| 201 | + let input = vec![1, 2, 3, 2, 4, 1, 5]; |
| 202 | + let result: Vec<i32> = input.into_iter().uniques().collect(); |
| 203 | + assert_eq!(result, vec![1, 2, 3, 4, 5]); |
| 204 | + } |
| 205 | + |
| 206 | + #[test] |
| 207 | + fn test_uniques_strings() { |
| 208 | + let input = vec!["a", "b", "c", "b", "a", "d"]; |
| 209 | + let result: Vec<&str> = input.into_iter().uniques().collect(); |
| 210 | + assert_eq!(result, vec!["a", "b", "c", "d"]); |
| 211 | + } |
| 212 | + |
| 213 | + #[test] |
| 214 | + fn test_empty() { |
| 215 | + let input: Vec<i32> = vec![]; |
| 216 | + let result: Vec<i32> = input.into_iter().uniques().collect(); |
| 217 | + assert_eq!(result, vec![]); |
| 218 | + } |
| 219 | +} |
0 commit comments