use crate::eval::functions::check_arity;
use crate::types::{ErrorKind, Value};
pub fn trimmean_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 2, 2) {
return err;
}
let percent = match &args[1] {
Value::Number(p) => *p,
_ => return Value::Error(ErrorKind::Value),
};
if !(0.0..1.0).contains(&percent) {
return Value::Error(ErrorKind::Num);
}
let mut nums: Vec<f64> = Vec::new();
match &args[0] {
Value::Number(n) => nums.push(*n),
Value::Array(arr) => {
for v in arr {
if let Value::Number(n) = v {
nums.push(*n);
}
}
}
_ => {}
}
if nums.is_empty() {
return Value::Error(ErrorKind::Num);
}
nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
let trim = (nums.len() as f64 * percent / 2.0).floor() as usize;
let trimmed = &nums[trim..nums.len() - trim];
if trimmed.is_empty() {
return Value::Error(ErrorKind::Num);
}
let mean = trimmed.iter().sum::<f64>() / trimmed.len() as f64;
if !mean.is_finite() {
return Value::Error(ErrorKind::Num);
}
Value::Number(mean)
}
#[cfg(test)]
mod tests;