use std::{cmp::Ordering, ops::AddAssign};
use num::{Float, NumCast};
pub fn count<T>(data: &[T]) -> usize {
data.iter().count()
}
pub fn min<T>(data: &[T]) -> Option<T>
where
T: PartialOrd + Copy,
{
if data.is_empty() {
return None;
}
let mut min_result = data[0];
for &item in data.iter().skip(1) {
if min_result > item {
min_result = item;
}
}
Some(min_result)
}
pub fn max<T>(data: &[T]) -> Option<T>
where
T: PartialOrd + Copy,
{
if data.is_empty() {
return None;
}
let mut max_result = data[0];
for &item in data.iter().skip(1) {
if max_result < item {
max_result = item;
}
}
Some(max_result)
}
pub fn avg<T>(data: &[T]) -> Option<f64>
where
T: std::convert::Into<f64> + Copy,
{
if data.is_empty() {
return None;
}
let mut result = 0.0;
let mut count = 0;
for &item in data {
let value: f64 = item.into();
result += value;
count += 1;
}
Some(result / count as f64)
}
pub fn median<T>(numbers: &[T]) -> Option<T>
where
T: PartialOrd + Clone,
{
if numbers.is_empty() {
return None;
}
let len = numbers.len();
let mid = len / 2;
if len == 1 {
return Some(numbers[0].clone());
}
let mut sorted_numbers = numbers.to_vec();
sorted_numbers.sort_by(|a, b| {
a.partial_cmp(b).unwrap_or_else(|| {
Ordering::Equal
})
});
if len % 2 == 0 {
Some(sorted_numbers[mid - 1].clone())
} else {
Some(sorted_numbers[mid].clone())
}
}
pub fn std_dev<T, U>(data: &[T]) -> U
where
T: NumCast + Copy,
U: Float + AddAssign + NumCast,
{
if data.len() < 2 {
return U::zero();
}
let n = U::from(data.len()).unwrap();
let n_minus_one = U::from(data.len() - 1).unwrap();
let sum = data.iter()
.map(|&x| U::from(x).unwrap())
.fold(U::zero(), |acc, x| acc + x);
let mean = sum / n;
let variance = data.iter()
.map(|&x| {
let val = U::from(x).unwrap();
let diff = val - mean;
diff * diff
})
.fold(U::zero(), |acc, x| acc + x) / n_minus_one;
variance.sqrt()
}