rollercoaster/unique.rs
1use std::{collections::HashSet, hash::Hash};
2
3pub struct Unique<I, K, F> {
4 seen: HashSet<K>,
5 underlying: I,
6 identify: F,
7}
8
9impl<I, K, F> Unique<I, K, F>
10where
11 I: Iterator,
12 K: Hash,
13 F: FnMut(&I::Item) -> K,
14{
15 pub(crate) fn new(iter: I, identify: F) -> Self {
16 Self {
17 seen: Default::default(),
18 underlying: iter,
19 identify,
20 }
21 }
22}
23
24impl<I, K, F> Iterator for Unique<I, K, F>
25where
26 I: Iterator,
27 K: Eq + Hash,
28 F: FnMut(&I::Item) -> K,
29{
30 type Item = I::Item;
31
32 fn next(&mut self) -> Option<Self::Item> {
33 let item = self.underlying.find(|i| {
34 let key = (self.identify)(i);
35 !self.seen.contains(&key)
36 });
37
38 if let Some(i) = item.as_ref() {
39 let key = (self.identify)(i);
40 self.seen.insert(key);
41 }
42
43 item
44 }
45}
46
47ext_impl! {
48 /// Creates an iterator that returns only unique values.
49 ///
50 /// The closure `F` is called on each item, where the returned value `K`
51 /// is checked against a [HashSet](std::collections::HashSet).
52 /// This means that `K` must implement
53 /// [Hash] + [Eq].
54 ///
55 /// If you are working with simple values, you can try
56 /// using [`unique`](crate::Rollercoaster::unique) instead.
57 ///
58 /// # Example
59 /// ```
60 /// # use rollercoaster::Rollercoaster;
61 /// let words = vec![
62 /// "I",
63 /// "A",
64 /// "am",
65 /// "no",
66 /// "to",
67 /// "ha",
68 /// "unique",
69 /// "people",
70 /// "me",
71 /// ];
72 ///
73 /// let result: Vec<_> = words
74 /// .into_iter()
75 /// .unique_by(|s| s.len())
76 /// .collect();
77 ///
78 /// assert_eq!(result, vec!["I", "am", "unique"]);
79 /// ```
80 fn unique_by<K, F>(self, identify: F) -> Unique<Self, K, F>
81 where
82 K: Hash + Eq,
83 F: FnMut(&Self::Item) -> K
84 {
85 Unique::new(self, identify)
86 }
87
88
89 /// Creates an iterator that returns unique values.
90 ///
91 /// Each value is cloned and checked against a [HashSet](std::collections::HashSet).
92 /// This means [`Item`](Iterator::Item) must implement
93 /// [Eq] + [Hash] + [Copy].
94 ///
95 /// If you need to specify a custom key per item,
96 /// use [`unique_by()`](crate::Rollercoaster::unique_by) instead.
97 ///
98 /// # Example
99 /// ```
100 /// # use rollercoaster::Rollercoaster;
101 /// let result: Vec<_> = vec![1, 1, 4, 5, 2, 1, 4, 3, 2]
102 /// .into_iter()
103 /// .unique()
104 /// .collect();
105 ///
106 /// assert_eq!(result, vec![1, 4, 5, 2, 3]);
107 /// ```
108 fn unique(self) -> Unique<Self, Self::Item, fn(&Self::Item) -> Self::Item>
109 where
110 Self::Item: Hash + Eq + Copy
111 {
112 Unique::new(self, |i| *i)
113 }
114}
115
116#[cfg(test)]
117mod test {
118 use crate::Rollercoaster;
119
120 #[test]
121 fn it_returns_unique() {
122 let result: Vec<_> = vec![5, 2, 6, 7, 3, 3, 2, 4, 5]
123 .into_iter()
124 .unique()
125 .collect();
126
127 let result_two: Vec<_> = vec!["apple", "apple", "orange"]
128 .into_iter()
129 .unique_by(|s| s.len())
130 .collect();
131
132 assert_eq!(result, vec![5, 2, 6, 7, 3, 4]);
133 assert_eq!(result_two, vec!["apple", "orange"]);
134 }
135}