#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Window {
size: usize,
}
impl Window {
pub fn new(size: usize) -> Window {
assert!(size > 0, "Window::new requires a non-zero size");
Window { size }
}
pub fn mean(&self, values: &[f64]) -> Vec<f64> {
self.reduce(values, |window| {
let finite: Vec<f64> = window.iter().copied().filter(|v| v.is_finite()).collect();
if finite.is_empty() {
f64::NAN
} else {
finite.iter().sum::<f64>() / finite.len() as f64
}
})
}
pub fn sum(&self, values: &[f64]) -> Vec<f64> {
self.reduce(values, |window| {
window.iter().copied().filter(|v| v.is_finite()).sum()
})
}
pub fn min(&self, values: &[f64]) -> Vec<f64> {
self.reduce(values, |window| {
let min = window
.iter()
.copied()
.filter(|v| v.is_finite())
.fold(f64::INFINITY, f64::min);
if min.is_finite() { min } else { f64::NAN }
})
}
pub fn max(&self, values: &[f64]) -> Vec<f64> {
self.reduce(values, |window| {
let max = window
.iter()
.copied()
.filter(|v| v.is_finite())
.fold(f64::NEG_INFINITY, f64::max);
if max.is_finite() { max } else { f64::NAN }
})
}
fn reduce(&self, values: &[f64], reducer: impl Fn(&[f64]) -> f64) -> Vec<f64> {
(0..values.len())
.map(|end| {
let start = (end + 1).saturating_sub(self.size);
reducer(&values[start..=end])
})
.collect()
}
}
#[cfg(test)]
#[path = "tests/window_tests.rs"]
mod tests;