Add GEOMEAN to Functions
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
5f3856350b
commit
4c3374c0de
@@ -140,6 +140,7 @@ pub enum Function {
|
|||||||
Countifs,
|
Countifs,
|
||||||
Maxifs,
|
Maxifs,
|
||||||
Minifs,
|
Minifs,
|
||||||
|
Geomean,
|
||||||
|
|
||||||
// Date and time
|
// Date and time
|
||||||
Date,
|
Date,
|
||||||
@@ -248,7 +249,7 @@ pub enum Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
pub fn into_iter() -> IntoIter<Function, 194> {
|
pub fn into_iter() -> IntoIter<Function, 195> {
|
||||||
[
|
[
|
||||||
Function::And,
|
Function::And,
|
||||||
Function::False,
|
Function::False,
|
||||||
@@ -348,6 +349,7 @@ impl Function {
|
|||||||
Function::Countifs,
|
Function::Countifs,
|
||||||
Function::Maxifs,
|
Function::Maxifs,
|
||||||
Function::Minifs,
|
Function::Minifs,
|
||||||
|
Function::Geomean,
|
||||||
Function::Year,
|
Function::Year,
|
||||||
Function::Day,
|
Function::Day,
|
||||||
Function::Month,
|
Function::Month,
|
||||||
@@ -611,6 +613,7 @@ impl Function {
|
|||||||
"COUNTIFS" => Some(Function::Countifs),
|
"COUNTIFS" => Some(Function::Countifs),
|
||||||
"MAXIFS" | "_XLFN.MAXIFS" => Some(Function::Maxifs),
|
"MAXIFS" | "_XLFN.MAXIFS" => Some(Function::Maxifs),
|
||||||
"MINIFS" | "_XLFN.MINIFS" => Some(Function::Minifs),
|
"MINIFS" | "_XLFN.MINIFS" => Some(Function::Minifs),
|
||||||
|
"GEOMEAN" => Some(Function::Geomean),
|
||||||
// Date and Time
|
// Date and Time
|
||||||
"YEAR" => Some(Function::Year),
|
"YEAR" => Some(Function::Year),
|
||||||
"DAY" => Some(Function::Day),
|
"DAY" => Some(Function::Day),
|
||||||
@@ -818,6 +821,7 @@ impl fmt::Display for Function {
|
|||||||
Function::Countifs => write!(f, "COUNTIFS"),
|
Function::Countifs => write!(f, "COUNTIFS"),
|
||||||
Function::Maxifs => write!(f, "MAXIFS"),
|
Function::Maxifs => write!(f, "MAXIFS"),
|
||||||
Function::Minifs => write!(f, "MINIFS"),
|
Function::Minifs => write!(f, "MINIFS"),
|
||||||
|
Function::Geomean => write!(f, "GEOMEAN"),
|
||||||
Function::Year => write!(f, "YEAR"),
|
Function::Year => write!(f, "YEAR"),
|
||||||
Function::Day => write!(f, "DAY"),
|
Function::Day => write!(f, "DAY"),
|
||||||
Function::Month => write!(f, "MONTH"),
|
Function::Month => write!(f, "MONTH"),
|
||||||
@@ -1054,6 +1058,7 @@ impl Model {
|
|||||||
Function::Countifs => self.fn_countifs(args, cell),
|
Function::Countifs => self.fn_countifs(args, cell),
|
||||||
Function::Maxifs => self.fn_maxifs(args, cell),
|
Function::Maxifs => self.fn_maxifs(args, cell),
|
||||||
Function::Minifs => self.fn_minifs(args, cell),
|
Function::Minifs => self.fn_minifs(args, cell),
|
||||||
|
Function::Geomean => self.fn_geomean(args, cell),
|
||||||
// Date and Time
|
// Date and Time
|
||||||
Function::Year => self.fn_year(args, cell),
|
Function::Year => self.fn_year(args, cell),
|
||||||
Function::Day => self.fn_day(args, cell),
|
Function::Day => self.fn_day(args, cell),
|
||||||
|
|||||||
@@ -635,4 +635,85 @@ impl Model {
|
|||||||
}
|
}
|
||||||
CalcResult::Number(max)
|
CalcResult::Number(max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn fn_geomean(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult{
|
||||||
|
if args.is_empty() {
|
||||||
|
return CalcResult::new_args_number_error(cell);
|
||||||
|
}
|
||||||
|
let mut count = 0.0;
|
||||||
|
let mut product = 1.0;
|
||||||
|
for arg in args {
|
||||||
|
match self.evaluate_node_in_context(arg, cell) {
|
||||||
|
CalcResult::Number(value) => {
|
||||||
|
count += 1.0;
|
||||||
|
product *= value;
|
||||||
|
}
|
||||||
|
CalcResult::Boolean(b) => {
|
||||||
|
if let Node::ReferenceKind { .. } = arg {
|
||||||
|
} else {
|
||||||
|
product *= if b { 1.0 } else { 0.0 };
|
||||||
|
count += 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CalcResult::Range { left, right } => {
|
||||||
|
if left.sheet != right.sheet {
|
||||||
|
return CalcResult::new_error(
|
||||||
|
Error::VALUE,
|
||||||
|
cell,
|
||||||
|
"Ranges are in different sheets".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for row in left.row..(right.row + 1) {
|
||||||
|
for column in left.column..(right.column + 1) {
|
||||||
|
match self.evaluate_cell(CellReferenceIndex {
|
||||||
|
sheet: left.sheet,
|
||||||
|
row,
|
||||||
|
column,
|
||||||
|
}) {
|
||||||
|
CalcResult::Number(value) => {
|
||||||
|
count += 1.0;
|
||||||
|
product *= value;
|
||||||
|
}
|
||||||
|
error @ CalcResult::Error { .. } => return error,
|
||||||
|
CalcResult::Range { .. } => {
|
||||||
|
return CalcResult::new_error(
|
||||||
|
Error::ERROR,
|
||||||
|
cell,
|
||||||
|
"Unexpected Range".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error @ CalcResult::Error { .. } => return error,
|
||||||
|
CalcResult::String(s) => {
|
||||||
|
if let Node::ReferenceKind { .. } = arg {
|
||||||
|
// Do nothing
|
||||||
|
} else if let Ok(t) = s.parse::<f64>() {
|
||||||
|
product *= t;
|
||||||
|
count += 1.0;
|
||||||
|
} else {
|
||||||
|
return CalcResult::Error {
|
||||||
|
error: Error::VALUE,
|
||||||
|
origin: cell,
|
||||||
|
message: "Argument cannot be cast into number".to_string(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Ignore everything else
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if count == 0.0 {
|
||||||
|
return CalcResult::Error {
|
||||||
|
error: Error::DIV,
|
||||||
|
origin: cell,
|
||||||
|
message: "Division by Zero".to_string(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
CalcResult::Number(product.powf(1.0/count))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user