dedup iter adapter
This commit is contained in:
parent
15b8ec562c
commit
9511f49163
|
@ -16,3 +16,4 @@ pub mod v2_types;
|
||||||
|
|
||||||
pub mod any_type;
|
pub mod any_type;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod util;
|
||||||
|
|
210
unreal-sdk/src/util.rs
Normal file
210
unreal-sdk/src/util.rs
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
pub struct DedupIdentity;
|
||||||
|
|
||||||
|
pub trait DedupGetHash<T> {
|
||||||
|
type Hashed: Hash + Eq;
|
||||||
|
fn get_hash<'a>(&mut self, a: &'a T) -> Self::Hashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DedupGetHash<T> for DedupIdentity
|
||||||
|
where
|
||||||
|
T: Hash + Eq + Clone,
|
||||||
|
{
|
||||||
|
type Hashed = T;
|
||||||
|
|
||||||
|
fn get_hash<'a>(&mut self, a: &'a T) -> Self::Hashed {
|
||||||
|
a.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T, H> DedupGetHash<T> for F
|
||||||
|
where
|
||||||
|
F: FnMut(&T) -> H,
|
||||||
|
H: Hash + Eq,
|
||||||
|
{
|
||||||
|
type Hashed = H;
|
||||||
|
|
||||||
|
fn get_hash<'a>(&mut self, a: &'a T) -> Self::Hashed {
|
||||||
|
self(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DedupWithBy<I, F, H>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(usize, <I as Iterator>::Item) -> <I as Iterator>::Item,
|
||||||
|
H: DedupGetHash<<I as Iterator>::Item>,
|
||||||
|
{
|
||||||
|
iter: I,
|
||||||
|
/// makes item unique, is told how many elements of this equality.
|
||||||
|
cb_fn: F,
|
||||||
|
/// returns the borrowed element by which to compare the iterators elements
|
||||||
|
hash_fn: H,
|
||||||
|
cache: HashMap<H::Hashed, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DedupIter: Iterator {
|
||||||
|
fn dedup_with<'a, F>(self, f: F) -> DedupWithBy<Self, F, DedupIdentity>
|
||||||
|
where
|
||||||
|
F: FnMut(usize, <Self as Iterator>::Item) -> <Self as Iterator>::Item,
|
||||||
|
Self: Sized,
|
||||||
|
<Self as Iterator>::Item: Eq + Hash + Clone,
|
||||||
|
{
|
||||||
|
DedupWithBy {
|
||||||
|
iter: self,
|
||||||
|
cb_fn: f,
|
||||||
|
hash_fn: DedupIdentity,
|
||||||
|
cache: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dedup_with_by<'a, F, H>(self, f: F, h: H) -> DedupWithBy<Self, F, H>
|
||||||
|
where
|
||||||
|
F: FnMut(usize, <Self as Iterator>::Item) -> <Self as Iterator>::Item,
|
||||||
|
H: DedupGetHash<<Self as Iterator>::Item>,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
DedupWithBy {
|
||||||
|
iter: self,
|
||||||
|
cb_fn: f,
|
||||||
|
hash_fn: h,
|
||||||
|
cache: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> DedupIter for I where I: Iterator {}
|
||||||
|
|
||||||
|
impl<I, F, H> Iterator for DedupWithBy<I, F, H>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(usize, <I as Iterator>::Item) -> <I as Iterator>::Item,
|
||||||
|
H: DedupGetHash<<I as Iterator>::Item>,
|
||||||
|
{
|
||||||
|
type Item = <I as Iterator>::Item;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let mut next = self.iter.next()?;
|
||||||
|
|
||||||
|
let next = loop {
|
||||||
|
let hash = self.hash_fn.get_hash(&next);
|
||||||
|
|
||||||
|
match self.cache.entry(hash) {
|
||||||
|
Entry::Occupied(mut entry) => {
|
||||||
|
*entry.get_mut() += 1;
|
||||||
|
|
||||||
|
next = (self.cb_fn)(*entry.get(), next);
|
||||||
|
}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(0);
|
||||||
|
break next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn numbers() {
|
||||||
|
let numbers = [1, 2, 2, 2, 3, 4, 5, 6, 22];
|
||||||
|
|
||||||
|
let unique = numbers
|
||||||
|
.into_iter()
|
||||||
|
.dedup_with(|n, i| (i * 10 + n) as usize)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(&unique, &[1, 2, 21, 22, 3, 4, 5, 6, 221]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
struct Key {
|
||||||
|
number: usize,
|
||||||
|
other: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keys() {
|
||||||
|
let keys = [
|
||||||
|
Key {
|
||||||
|
number: 1,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 2,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 2,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 2,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 3,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 4,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 5,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let expected = [
|
||||||
|
Key {
|
||||||
|
number: 1,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 2,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 21,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 22,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 3,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 4,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
Key {
|
||||||
|
number: 5,
|
||||||
|
other: 1.0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let unique = keys
|
||||||
|
.into_iter()
|
||||||
|
.dedup_with_by(
|
||||||
|
|n, key| Key {
|
||||||
|
number: (key.number * 10 + n),
|
||||||
|
..key
|
||||||
|
},
|
||||||
|
|key: &Key| -> usize { key.number },
|
||||||
|
)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(&unique, &expected);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue