/rust/registry/src/index.crates.io-1949cf8c6b5b557f/itertools-0.12.1/src/unique_impl.rs
Line | Count | Source |
1 | | use std::collections::hash_map::Entry; |
2 | | use std::collections::HashMap; |
3 | | use std::fmt; |
4 | | use std::hash::Hash; |
5 | | use std::iter::FusedIterator; |
6 | | |
7 | | /// An iterator adapter to filter out duplicate elements. |
8 | | /// |
9 | | /// See [`.unique_by()`](crate::Itertools::unique) for more information. |
10 | | #[derive(Clone)] |
11 | | #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] |
12 | | pub struct UniqueBy<I: Iterator, V, F> { |
13 | | iter: I, |
14 | | // Use a Hashmap for the Entry API in order to prevent hashing twice. |
15 | | // This can maybe be replaced with a HashSet once `get_or_insert_with` |
16 | | // or a proper Entry API for Hashset is stable and meets this msrv |
17 | | used: HashMap<V, ()>, |
18 | | f: F, |
19 | | } |
20 | | |
21 | | impl<I, V, F> fmt::Debug for UniqueBy<I, V, F> |
22 | | where |
23 | | I: Iterator + fmt::Debug, |
24 | | V: fmt::Debug + Hash + Eq, |
25 | | { |
26 | | debug_fmt_fields!(UniqueBy, iter, used); |
27 | | } |
28 | | |
29 | | /// Create a new `UniqueBy` iterator. |
30 | 0 | pub fn unique_by<I, V, F>(iter: I, f: F) -> UniqueBy<I, V, F> |
31 | 0 | where |
32 | 0 | V: Eq + Hash, |
33 | 0 | F: FnMut(&I::Item) -> V, |
34 | 0 | I: Iterator, |
35 | | { |
36 | 0 | UniqueBy { |
37 | 0 | iter, |
38 | 0 | used: HashMap::new(), |
39 | 0 | f, |
40 | 0 | } |
41 | 0 | } |
42 | | |
43 | | // count the number of new unique keys in iterable (`used` is the set already seen) |
44 | 0 | fn count_new_keys<I, K>(mut used: HashMap<K, ()>, iterable: I) -> usize |
45 | 0 | where |
46 | 0 | I: IntoIterator<Item = K>, |
47 | 0 | K: Hash + Eq, |
48 | | { |
49 | 0 | let iter = iterable.into_iter(); |
50 | 0 | let current_used = used.len(); |
51 | 0 | used.extend(iter.map(|key| (key, ()))); |
52 | 0 | used.len() - current_used |
53 | 0 | } |
54 | | |
55 | | impl<I, V, F> Iterator for UniqueBy<I, V, F> |
56 | | where |
57 | | I: Iterator, |
58 | | V: Eq + Hash, |
59 | | F: FnMut(&I::Item) -> V, |
60 | | { |
61 | | type Item = I::Item; |
62 | | |
63 | 0 | fn next(&mut self) -> Option<Self::Item> { |
64 | 0 | let Self { iter, used, f } = self; |
65 | 0 | iter.find(|v| used.insert(f(v), ()).is_none()) |
66 | 0 | } |
67 | | |
68 | | #[inline] |
69 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
70 | 0 | let (low, hi) = self.iter.size_hint(); |
71 | 0 | ((low > 0 && self.used.is_empty()) as usize, hi) |
72 | 0 | } |
73 | | |
74 | 0 | fn count(self) -> usize { |
75 | 0 | let mut key_f = self.f; |
76 | 0 | count_new_keys(self.used, self.iter.map(move |elt| key_f(&elt))) |
77 | 0 | } |
78 | | } |
79 | | |
80 | | impl<I, V, F> DoubleEndedIterator for UniqueBy<I, V, F> |
81 | | where |
82 | | I: DoubleEndedIterator, |
83 | | V: Eq + Hash, |
84 | | F: FnMut(&I::Item) -> V, |
85 | | { |
86 | 0 | fn next_back(&mut self) -> Option<Self::Item> { |
87 | 0 | let Self { iter, used, f } = self; |
88 | 0 | iter.rfind(|v| used.insert(f(v), ()).is_none()) |
89 | 0 | } |
90 | | } |
91 | | |
92 | | impl<I, V, F> FusedIterator for UniqueBy<I, V, F> |
93 | | where |
94 | | I: FusedIterator, |
95 | | V: Eq + Hash, |
96 | | F: FnMut(&I::Item) -> V, |
97 | | { |
98 | | } |
99 | | |
100 | | impl<I> Iterator for Unique<I> |
101 | | where |
102 | | I: Iterator, |
103 | | I::Item: Eq + Hash + Clone, |
104 | | { |
105 | | type Item = I::Item; |
106 | | |
107 | 0 | fn next(&mut self) -> Option<Self::Item> { |
108 | 0 | let UniqueBy { iter, used, .. } = &mut self.iter; |
109 | 0 | iter.find_map(|v| { |
110 | 0 | if let Entry::Vacant(entry) = used.entry(v) { |
111 | 0 | let elt = entry.key().clone(); |
112 | 0 | entry.insert(()); |
113 | 0 | return Some(elt); |
114 | 0 | } |
115 | 0 | None |
116 | 0 | }) |
117 | 0 | } |
118 | | |
119 | | #[inline] |
120 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
121 | 0 | let (low, hi) = self.iter.iter.size_hint(); |
122 | 0 | ((low > 0 && self.iter.used.is_empty()) as usize, hi) |
123 | 0 | } |
124 | | |
125 | 0 | fn count(self) -> usize { |
126 | 0 | count_new_keys(self.iter.used, self.iter.iter) |
127 | 0 | } |
128 | | } |
129 | | |
130 | | impl<I> DoubleEndedIterator for Unique<I> |
131 | | where |
132 | | I: DoubleEndedIterator, |
133 | | I::Item: Eq + Hash + Clone, |
134 | | { |
135 | 0 | fn next_back(&mut self) -> Option<Self::Item> { |
136 | 0 | let UniqueBy { iter, used, .. } = &mut self.iter; |
137 | 0 | iter.rev().find_map(|v| { |
138 | 0 | if let Entry::Vacant(entry) = used.entry(v) { |
139 | 0 | let elt = entry.key().clone(); |
140 | 0 | entry.insert(()); |
141 | 0 | return Some(elt); |
142 | 0 | } |
143 | 0 | None |
144 | 0 | }) |
145 | 0 | } |
146 | | } |
147 | | |
148 | | impl<I> FusedIterator for Unique<I> |
149 | | where |
150 | | I: FusedIterator, |
151 | | I::Item: Eq + Hash + Clone, |
152 | | { |
153 | | } |
154 | | |
155 | | /// An iterator adapter to filter out duplicate elements. |
156 | | /// |
157 | | /// See [`.unique()`](crate::Itertools::unique) for more information. |
158 | | #[derive(Clone)] |
159 | | #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] |
160 | | pub struct Unique<I> |
161 | | where |
162 | | I: Iterator, |
163 | | I::Item: Eq + Hash + Clone, |
164 | | { |
165 | | iter: UniqueBy<I, I::Item, ()>, |
166 | | } |
167 | | |
168 | | impl<I> fmt::Debug for Unique<I> |
169 | | where |
170 | | I: Iterator + fmt::Debug, |
171 | | I::Item: Hash + Eq + fmt::Debug + Clone, |
172 | | { |
173 | | debug_fmt_fields!(Unique, iter); |
174 | | } |
175 | | |
176 | 0 | pub fn unique<I>(iter: I) -> Unique<I> |
177 | 0 | where |
178 | 0 | I: Iterator, |
179 | 0 | I::Item: Eq + Hash + Clone, |
180 | | { |
181 | 0 | Unique { |
182 | 0 | iter: UniqueBy { |
183 | 0 | iter, |
184 | 0 | used: HashMap::new(), |
185 | 0 | f: (), |
186 | 0 | }, |
187 | 0 | } |
188 | 0 | } |