use std::{collections::HashSet, hash::Hash};
pub struct Unique<I, K, F> {
seen: HashSet<K>,
underlying: I,
identify: F,
}
impl<I, K, F> Unique<I, K, F>
where
I: Iterator,
K: Hash,
F: FnMut(&I::Item) -> K,
{
pub(crate) fn new(iter: I, identify: F) -> Self {
Self {
seen: Default::default(),
underlying: iter,
identify,
}
}
}
impl<I, K, F> Iterator for Unique<I, K, F>
where
I: Iterator,
K: Eq + Hash,
F: FnMut(&I::Item) -> K,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let item = self.underlying.find(|i| {
let key = (self.identify)(i);
!self.seen.contains(&key)
});
if let Some(i) = item.as_ref() {
let key = (self.identify)(i);
self.seen.insert(key);
}
item
}
}
ext_impl! {
fn unique_by<K, F>(self, identify: F) -> Unique<Self, K, F>
where
K: Hash + Eq,
F: FnMut(&Self::Item) -> K
{
Unique::new(self, identify)
}
fn unique(self) -> Unique<Self, Self::Item, fn(&Self::Item) -> Self::Item>
where
Self::Item: Hash + Eq + Copy
{
Unique::new(self, |i| *i)
}
}
#[cfg(test)]
mod test {
use crate::Rollercoaster;
#[test]
fn it_returns_unique() {
let result: Vec<_> = vec![5, 2, 6, 7, 3, 3, 2, 4, 5]
.into_iter()
.unique()
.collect();
let result_two: Vec<_> = vec!["apple", "apple", "orange"]
.into_iter()
.unique_by(|s| s.len())
.collect();
assert_eq!(result, vec![5, 2, 6, 7, 3, 4]);
assert_eq!(result_two, vec!["apple", "orange"]);
}
}