use crate::argsort::{ArgSort, ArgSortIter};
use crate::Iterstats;
pub trait Rank<A = Self>: Sized {
fn rank<I: Iterator<Item = A>>(iter: I) -> RankIter;
}
impl<T> Rank for T
where
T: ArgSort,
{
fn rank<I: Iterator<Item = Self>>(iter: I) -> RankIter {
RankIter::new(iter)
}
}
pub struct RankIter {
nested_argsort: ArgSortIter<usize>,
}
impl RankIter {
fn new<T: ArgSort>(iter: impl Iterator<Item = T>) -> Self {
Self {
nested_argsort: iter.argsort().argsort(),
}
}
}
impl Iterator for RankIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
self.nested_argsort.next()
}
}
#[cfg(test)]
mod tests {
use super::*;
use paste::paste;
macro_rules! test_rank {
($name:ident : $typ:ty as $input:expr => $expected:expr) => {
paste! {
#[test]
fn [<$name _iter>]() {
let output = <&$typ>::rank($input.iter()).collect::<Vec<usize>>();
assert_eq!(output, $expected)
}
}
paste! {
#[test]
fn [<$name _into_iter>]() {
let output = $typ::rank($input.into_iter()).collect::<Vec<usize>>();
assert_eq!(output, $expected)
}
}
};
}
test_rank!(usize_ordered : usize as [0, 1, 2, 3, 4, 5] => vec![0, 1, 2, 3, 4, 5]);
test_rank!(usize_reversed : usize as [5, 4, 3, 2, 1] => vec![4, 3, 2, 1, 0]);
test_rank!(char : char as ['d', 'a', 'c', 'b', 'z', 'y'] => vec![3, 0, 2, 1, 5, 4]);
test_rank!(f32 : f32 as [f32::NAN, 4.2, 0.0, f32::NEG_INFINITY, -0.0, f32::INFINITY, -f32::NAN]
=> vec![ 6, 4, 3, 1, 2, 5, 0]
);
test_rank!(f64 : f64 as [f64::NAN, 4.2, 0.0, f64::NEG_INFINITY, -0.0, f64::INFINITY, -f64::NAN]
=> vec![ 6, 4, 3, 1, 2, 5, 0]
);
}