use crate::types::{ErrorKind, Value};
fn collect_nums(args: &[Value]) -> Result<Vec<f64>, Value> {
let mut nums: Vec<f64> = Vec::new();
for arg in args {
match arg {
Value::Number(n) => nums.push(*n),
Value::Array(arr) => {
for v in arr {
match v {
Value::Number(n) => nums.push(*n),
Value::Error(e) => return Err(Value::Error(e.clone())),
_ => {}
}
}
}
Value::Error(e) => return Err(Value::Error(e.clone())),
_ => {}
}
}
Ok(nums)
}
pub fn mode_single(nums: &[f64]) -> Value {
if nums.is_empty() {
return Value::Error(ErrorKind::NA);
}
let mut sorted = nums.to_vec();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mut best_val = sorted[0];
let mut best_count = 0usize;
let mut cur_val = sorted[0];
let mut cur_count = 0usize;
for &x in &sorted {
if x == cur_val {
cur_count += 1;
} else {
if cur_count > best_count {
best_count = cur_count;
best_val = cur_val;
}
cur_val = x;
cur_count = 1;
}
}
if cur_count > best_count {
best_count = cur_count;
best_val = cur_val;
}
if best_count < 2 {
return Value::Error(ErrorKind::NA);
}
Value::Number(best_val)
}
pub fn mode_fn(args: &[Value]) -> Value {
match collect_nums(args) {
Ok(nums) => mode_single(&nums),
Err(e) => e,
}
}
#[cfg(test)]
mod tests;