iter_extra/prelude.rs
1pub struct Deltas<I: Iterator> {
2 pub(crate) items: Vec<(I::Item, usize)>,
3 pub(crate) enumerate_iter: std::iter::Enumerate<I>,
4}
5
6impl<I: Iterator> Deltas<I> {
7 pub(crate) fn new(iter: I) -> Self {
8 Deltas {
9 items: Vec::new(),
10 enumerate_iter: iter.enumerate(),
11 }
12 }
13}
14
15impl<I: Iterator> Iterator for Deltas<I>
16where
17 I::Item: std::cmp::PartialEq,
18{
19 type Item = usize;
20
21 fn next(&mut self) -> Option<Self::Item> {
22 let (next_index, next_item) = self.enumerate_iter.next()?;
23
24 let last_index = (self.items.iter().rev())
25 .find_map(|(item, index)| (item == &next_item).then_some(*index));
26
27 self.items.push((next_item, next_index));
28 Some(last_index.map_or(next_index, |last_idx| next_index - last_idx - 1))
29 }
30}
31
32pub struct DeltasBy<I: Iterator, F> {
33 items: Vec<(I::Item, usize)>,
34 enumerate_iter: std::iter::Enumerate<I>,
35 cmp_fn: F,
36}
37
38impl<I: Iterator, F> DeltasBy<I, F> {
39 pub(crate) fn new(iter: I, cmp_fn: F) -> Self {
40 DeltasBy {
41 items: Vec::new(),
42 enumerate_iter: iter.enumerate(),
43 cmp_fn,
44 }
45 }
46}
47
48impl<I: Iterator, F> Iterator for DeltasBy<I, F>
49where
50 F: FnMut(&I::Item, &I::Item) -> std::cmp::Ordering,
51{
52 type Item = usize;
53
54 fn next(&mut self) -> Option<Self::Item> {
55 let (next_index, next_item) = self.enumerate_iter.next()?;
56
57 let last_index = (self.items.iter().rev()).find_map(|(item, index)| {
58 ((self.cmp_fn)(item, &next_item) == std::cmp::Ordering::Equal).then_some(*index)
59 });
60
61 self.items.push((next_item, next_index));
62 Some(last_index.map_or(next_index, |last_idx| next_index - last_idx - 1))
63 }
64}
65
66pub struct DeltasByKey<I: Iterator, F> {
67 items: Vec<(I::Item, usize)>,
68 enumerate_iter: std::iter::Enumerate<I>,
69 key_fn: F,
70}
71
72impl<I: Iterator, F> DeltasByKey<I, F> {
73 pub(crate) fn new(iter: I, key_fn: F) -> Self {
74 DeltasByKey {
75 items: Vec::new(),
76 enumerate_iter: iter.enumerate(),
77 key_fn,
78 }
79 }
80}
81
82impl<I: Iterator, K, F> Iterator for DeltasByKey<I, F>
83where
84 F: FnMut(&I::Item) -> K,
85 K: std::cmp::PartialEq,
86{
87 type Item = usize;
88
89 fn next(&mut self) -> Option<Self::Item> {
90 let (next_index, next_item) = self.enumerate_iter.next()?;
91
92 let next_key = (self.key_fn)(&next_item);
93 let last_index = (self.items.iter().rev())
94 .find_map(|(item, index)| ((self.key_fn)(item) == next_key).then_some(*index));
95
96 self.items.push((next_item, next_index));
97 Some(last_index.map_or(next_index, |last_idx| next_index - last_idx - 1))
98 }
99}
100
101pub trait IterExtra: Iterator {
102 /// Returns the element that gives the minimum value from the specified function.
103 ///
104 /// This method is similar to `Iterator::min_by_key`, but works with types that implement
105 /// `PartialOrd` instead of `Ord`. When the comparison returns `None` (indicating
106 /// incomparable values like NaN), it treats them as equal.
107 ///
108 /// # Arguments
109 ///
110 /// * `key` - A function that extracts a key from each element for comparison
111 ///
112 /// # Returns
113 ///
114 /// * `Some(item)` - The element that produces the minimum key value
115 /// * `None` - If the iterator is empty
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// use iter_extra::IterExtra;
121 ///
122 /// let numbers = vec![3.2, 1.5, 2.8, 0.9];
123 /// let min = numbers.iter().min_by_partial_key(|&x| x);
124 /// assert_eq!(min, Some(&0.9));
125 ///
126 /// // Works with NaN values
127 /// let with_nan = vec![1.0, f64::NAN, 2.0];
128 /// let min = with_nan.iter().min_by_partial_key(|&x| x);
129 /// assert_eq!(min, Some(&1.0));
130 /// ```
131 fn min_by_partial_key<K: PartialOrd, F: FnMut(&Self::Item) -> K>(
132 self,
133 mut key: F,
134 ) -> Option<Self::Item>
135 where
136 Self: Sized,
137 {
138 self.min_by(|x, y| {
139 key(x)
140 .partial_cmp(&key(y))
141 .unwrap_or(std::cmp::Ordering::Equal)
142 })
143 }
144
145 /// Returns the element that gives the maximum value from the specified function.
146 ///
147 /// This method is similar to `Iterator::max_by_key`, but works with types that implement
148 /// `PartialOrd` instead of `Ord`. When the comparison returns `None` (indicating
149 /// incomparable values like NaN), it treats them as equal.
150 ///
151 /// # Arguments
152 ///
153 /// * `key` - A function that extracts a key from each element for comparison
154 ///
155 /// # Returns
156 ///
157 /// * `Some(item)` - The element that produces the maximum key value
158 /// * `None` - If the iterator is empty
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use iter_extra::IterExtra;
164 ///
165 /// let numbers = vec![3.2, 1.5, 2.8, 0.9];
166 /// let max = numbers.iter().max_by_partial_key(|&x| x);
167 /// assert_eq!(max, Some(&3.2));
168 ///
169 /// // Works with NaN values
170 /// let with_nan = vec![1.0, f64::NAN, 2.0];
171 /// let max = with_nan.iter().max_by_partial_key(|&x| x);
172 /// assert_eq!(max, Some(&2.0));
173 /// ```
174 fn max_by_partial_key<K: PartialOrd, F: FnMut(&Self::Item) -> K>(
175 self,
176 mut key: F,
177 ) -> Option<Self::Item>
178 where
179 Self: Sized,
180 {
181 self.max_by(|x, y| {
182 key(x)
183 .partial_cmp(&key(y))
184 .unwrap_or(std::cmp::Ordering::Equal)
185 })
186 }
187
188 fn collect_some_vec(self) -> Option<Vec<Self::Item>>
189 where
190 Self: Sized,
191 {
192 Some(self.collect::<Vec<Self::Item>>()).filter(|v| !v.is_empty())
193 }
194
195 fn collect_ok_vec_or<E>(self, err: E) -> Result<Vec<Self::Item>, E>
196 where
197 Self: Sized,
198 {
199 Ok(self.collect::<Vec<Self::Item>>()).and_then(
200 |v| {
201 if v.is_empty() { Err(err) } else { Ok(v) }
202 },
203 )
204 }
205
206 fn collect_ok_vec_or_default<E: Default>(self) -> Result<Vec<Self::Item>, E>
207 where
208 Self: Sized,
209 {
210 Ok(self.collect::<Vec<Self::Item>>()).and_then(|v| {
211 if v.is_empty() {
212 Err(E::default())
213 } else {
214 Ok(v)
215 }
216 })
217 }
218
219 /// Returns an iterator that yields the distance from each element to its last occurrence.
220 ///
221 /// For each element in the iterator, this method returns the number of elements between
222 /// the current element and the previous occurrence of the same element. If the element
223 /// hasn't appeared before, it returns the current index.
224 ///
225 /// # Returns
226 ///
227 /// An iterator that yields `usize` values representing the delta for each element
228 ///
229 /// # Examples
230 ///
231 /// ```
232 /// use iter_extra::IterExtra;
233 ///
234 /// let items = vec!['a', 'b', 'c', 'a', 'c'];
235 /// let deltas: Vec<usize> = items.into_iter().deltas().collect();
236 /// assert_eq!(deltas, vec![0, 1, 2, 2, 1]);
237 /// ```
238 fn deltas(self) -> Deltas<Self>
239 where
240 Self: Sized,
241 Self::Item: std::cmp::PartialEq,
242 {
243 Deltas::new(self)
244 }
245
246 /// Returns an iterator that yields the distance from each element to its last occurrence,
247 /// using a custom comparison function.
248 ///
249 /// Similar to `deltas`, but uses a custom comparison function to determine element equality.
250 /// Two elements are considered equal when the comparison function returns `Ordering::Equal`.
251 ///
252 /// # Arguments
253 ///
254 /// * `cmp_fn` - A function that compares two elements and returns an `Ordering`
255 ///
256 /// # Returns
257 ///
258 /// An iterator that yields `usize` values representing the delta for each element
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use iter_extra::IterExtra;
264 ///
265 /// let items = vec![1.1, 2.2, 3.3, 1.2, 2.1];
266 /// let deltas: Vec<usize> = items.into_iter()
267 /// .deltas_by(|a, b| a.floor().total_cmp(&b.floor()))
268 /// .collect();
269 /// assert_eq!(deltas, vec![0, 1, 2, 2, 2]);
270 /// ```
271 fn deltas_by<F>(self, cmp_fn: F) -> DeltasBy<Self, F>
272 where
273 Self: Sized,
274 F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering,
275 {
276 DeltasBy::new(self, cmp_fn)
277 }
278
279 /// Returns an iterator that yields the distance from each element to its last occurrence,
280 /// comparing elements by a key extracted from each element.
281 ///
282 /// Similar to `deltas`, but determines element equality by comparing the keys extracted
283 /// by the provided key function. Two elements are considered equal if their keys are equal.
284 ///
285 /// # Arguments
286 ///
287 /// * `key_fn` - A function that extracts a key from each element for comparison
288 ///
289 /// # Returns
290 ///
291 /// An iterator that yields `usize` values representing the delta for each element
292 ///
293 /// # Examples
294 ///
295 /// ```
296 /// use iter_extra::IterExtra;
297 ///
298 /// let items = vec!["apple", "banana", "apricot", "blueberry"];
299 /// let deltas: Vec<usize> = items.into_iter()
300 /// .deltas_by_key(|s| s.chars().next())
301 /// .collect();
302 /// assert_eq!(deltas, vec![0, 1, 1, 1]);
303 /// ```
304 fn deltas_by_key<K, F>(self, key_fn: F) -> DeltasByKey<Self, F>
305 where
306 Self: Sized,
307 F: FnMut(&Self::Item) -> K,
308 K: std::cmp::PartialEq,
309 {
310 DeltasByKey::new(self, key_fn)
311 }
312}
313
314impl<I: Iterator<Item = T>, T> IterExtra for I {}