use core::iter::Iterator;
use core::ops::{Deref, DerefMut};
pub struct NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
{
n: usize,
f: F,
candidates: Vec<T>,
}
impl<T, K, F> NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
{
pub fn new(n: usize, f: F) -> Self {
Self {
n,
f,
candidates: Vec::with_capacity(n),
}
}
pub fn into_vec(self) -> Vec<T> {
self.candidates
}
}
impl<T, K, F> NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
K: PartialOrd,
{
pub fn push(&mut self, mut candidate: T) -> Option<T> {
if self.candidates.len() < self.n {
self.candidates.push(candidate);
return None;
}
while let Some(to_replace) = self.candidates
.iter_mut()
.find(|item| (self.f)(&candidate).lt(&(self.f)(item)))
{
std::mem::swap(&mut candidate, to_replace);
}
Some(candidate)
}
}
impl<T, K, F> Deref for NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
{
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.candidates
}
}
impl<T, K, F> DerefMut for NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.candidates
}
}
impl<T, K, F> Into<Vec<T>> for NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
{
fn into(self) -> Vec<T> {
self.into_vec()
}
}
impl<T, K, F> IntoIterator for NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
{
type Item = T;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.candidates.into_iter()
}
}
pub trait TakeNBestByKey<T>
where
Self: Sized,
{
fn n_best_by_key<K, F>(self, n: usize, f: F) -> NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
K: PartialOrd;
}
impl<I, T> TakeNBestByKey<T> for I
where
I: Iterator<Item = T> + Sized
{
fn n_best_by_key<K, F>(self, n: usize, f: F) -> NBestByKey<T, K, F>
where
F: FnMut(&T) -> K,
K: PartialOrd,
{
let mut n_best = NBestByKey::new(n, f);
for item in self {
n_best.push(item);
}
n_best
}
}