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 {}