use crate::eval::functions::math::criterion::{flatten_to_vec, matches_criterion, parse_criterion};
use crate::types::{ErrorKind, Value};
pub fn averageifs_fn(args: &[Value]) -> Value {
if args.len() < 3 || args.len().is_multiple_of(2) {
return Value::Error(ErrorKind::NA);
}
if args.iter().step_by(2).any(|a| matches!(a, Value::Array(_))) {
return Value::Error(ErrorKind::NA);
}
let avg_range = flatten_to_vec(&args[0]);
let num_criteria = (args.len() - 1) / 2;
let mut total = 0.0_f64;
let mut count = 0usize;
'outer: for (i, a_val) in avg_range.iter().enumerate() {
for k in 0..num_criteria {
let crit_range = flatten_to_vec(&args[1 + k * 2]);
let crit = parse_criterion(&args[2 + k * 2]);
let crit_val = crit_range.get(i).copied().unwrap_or(&Value::Empty);
if !matches_criterion(crit_val, &crit) {
continue 'outer;
}
}
match a_val {
Value::Number(n) => {
total += n;
count += 1;
}
Value::Bool(b) => {
total += if *b { 1.0 } else { 0.0 };
count += 1;
}
_ => {}
}
}
if count == 0 {
return Value::Error(ErrorKind::DivByZero);
}
Value::Number(total / count as f64)
}
#[cfg(test)]
mod tests;