use crate::eval::functions::check_arity;
use crate::types::{ErrorKind, Value};
pub fn rank_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 2, 3) {
return err;
}
let x = match &args[0] {
Value::Number(n) => *n,
_ => return Value::Error(ErrorKind::NA),
};
let nums = collect_numbers(&args[1]);
let ascending = args.get(2).map(|v| match v {
Value::Number(n) => *n != 0.0,
_ => false,
}).unwrap_or(false);
rank_eq_impl(x, &nums, ascending)
}
fn rank_eq_impl(x: f64, nums: &[f64], ascending: bool) -> Value {
if nums.is_empty() {
return Value::Error(ErrorKind::NA);
}
if !nums.contains(&x) {
return Value::Error(ErrorKind::NA);
}
let rank = if ascending {
nums.iter().filter(|&&n| n < x).count() + 1
} else {
nums.iter().filter(|&&n| n > x).count() + 1
};
Value::Number(rank as f64)
}
fn collect_numbers(v: &Value) -> Vec<f64> {
match v {
Value::Array(arr) => arr.iter().filter_map(|x| {
if let Value::Number(n) = x { Some(*n) } else { None }
}).collect(),
Value::Number(n) => vec![*n],
_ => vec![],
}
}
#[cfg(test)]
mod tests;