dedup iter adapter

This commit is contained in:
Janis 2023-06-26 10:39:59 +02:00
parent 15b8ec562c
commit 9511f49163
2 changed files with 211 additions and 0 deletions

View file

@ -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
View 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);
}
}