use super::iterators::MovingAverageIterator;
use super::{QueryBuilder, QueryData};
use crate::core::state::Filtered;
use num_traits::ToPrimitive;
use std::marker::PhantomData;
use std::ops::Add;
impl<T: 'static, State> QueryBuilder<T, State> {
pub fn running_sum(self) -> QueryBuilder<T, Filtered>
where
T: Copy + Add<Output = T>,
{
let items = self.into_vec();
let mut out = Vec::with_capacity(items.len());
let mut acc: Option<T> = None;
for item in items {
acc = Some(match acc {
None => item,
Some(a) => a + item,
});
out.push(acc.unwrap());
}
QueryBuilder {
data: QueryData::Iterator(Box::new(out.into_iter())),
_state: PhantomData,
}
}
pub fn running_average(self) -> QueryBuilder<f64, Filtered>
where
T: ToPrimitive,
{
let items = self.into_vec();
let mut out = Vec::with_capacity(items.len());
let mut sum = 0.0f64;
for (i, item) in items.into_iter().enumerate() {
sum += item.to_f64().unwrap_or(0.0);
out.push(sum / (i + 1) as f64);
}
QueryBuilder {
data: QueryData::Iterator(Box::new(out.into_iter())),
_state: PhantomData,
}
}
pub fn moving_average(self, window: usize) -> QueryBuilder<Option<f64>, Filtered>
where
T: ToPrimitive,
{
assert!(window >= 1, "moving_average: window must be >= 1");
let floats: Vec<f64> = self
.into_vec()
.into_iter()
.map(|x| x.to_f64().unwrap_or(0.0))
.collect();
QueryBuilder {
data: QueryData::Iterator(Box::new(MovingAverageIterator::new(floats, window))),
_state: PhantomData,
}
}
pub fn rank_by<K, F>(self, key: F) -> QueryBuilder<(usize, T), Filtered>
where
K: Ord,
F: Fn(&T) -> K,
{
let items = self.into_vec();
let rank_map = build_rank_map(&items, &key, false);
let result: Vec<(usize, T)> = items
.into_iter()
.enumerate()
.map(|(i, x)| (rank_map[i], x))
.collect();
QueryBuilder {
data: QueryData::Iterator(Box::new(result.into_iter())),
_state: PhantomData,
}
}
pub fn dense_rank_by<K, F>(self, key: F) -> QueryBuilder<(usize, T), Filtered>
where
K: Ord,
F: Fn(&T) -> K,
{
let items = self.into_vec();
let rank_map = build_rank_map(&items, &key, true);
let result: Vec<(usize, T)> = items
.into_iter()
.enumerate()
.map(|(i, x)| (rank_map[i], x))
.collect();
QueryBuilder {
data: QueryData::Iterator(Box::new(result.into_iter())),
_state: PhantomData,
}
}
pub fn lag(self, n: usize) -> QueryBuilder<(Option<T>, T), Filtered>
where
T: Clone,
{
let items = self.into_vec();
let result: Vec<(Option<T>, T)> = items
.iter()
.enumerate()
.map(|(i, x)| {
let prev = if i >= n {
Some(items[i - n].clone())
} else {
None
};
(prev, x.clone())
})
.collect();
QueryBuilder {
data: QueryData::Iterator(Box::new(result.into_iter())),
_state: PhantomData,
}
}
pub fn lead(self, n: usize) -> QueryBuilder<(T, Option<T>), Filtered>
where
T: Clone,
{
let items = self.into_vec();
let len = items.len();
let result: Vec<(T, Option<T>)> = items
.iter()
.enumerate()
.map(|(i, x)| {
let next = if i + n < len {
Some(items[i + n].clone())
} else {
None
};
(x.clone(), next)
})
.collect();
QueryBuilder {
data: QueryData::Iterator(Box::new(result.into_iter())),
_state: PhantomData,
}
}
}
fn build_rank_map<T, K, F>(items: &[T], key: &F, dense: bool) -> Vec<usize>
where
K: Ord,
F: Fn(&T) -> K,
{
if items.is_empty() {
return vec![];
}
let mut keyed: Vec<(usize, K)> = items.iter().enumerate().map(|(i, x)| (i, key(x))).collect();
keyed.sort_by(|a, b| a.1.cmp(&b.1));
let mut rank_map = vec![0usize; items.len()];
let mut rank = 1usize;
let mut i = 0;
while i < keyed.len() {
let mut j = i + 1;
while j < keyed.len() && keyed[j].1 == keyed[i].1 {
j += 1;
}
for entry in &keyed[i..j] {
rank_map[entry.0] = rank;
}
rank = if dense { rank + 1 } else { rank + (j - i) };
i = j;
}
rank_map
}