Add sum and product to arrays (#966)

This commit is contained in:
SekoiaTree 2023-04-25 11:18:27 +02:00 committed by GitHub
parent 12129f0170
commit efad1e71fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 0 deletions

View File

@ -630,6 +630,20 @@ Folds all items into a single value using an accumulator function.
and one for an item.
- returns: any
### sum()
Sums all items (works for any types that can be added).
- default: any (named)
If set and the array is empty, sum will return this.
- returns: any
### product()
Calculates the product all items (works for any types that can be multiplied)
- default: any (named)
If set and the array is empty, sum will return this.
- returns: any
### any()
Whether the given function returns `{true}` for any item in the array.

View File

@ -24,6 +24,7 @@ macro_rules! __array {
#[doc(inline)]
pub use crate::__array as array;
use crate::eval::ops::{add, mul};
#[doc(hidden)]
pub use ecow::eco_vec;
@ -199,6 +200,40 @@ impl Array {
Ok(acc)
}
/// Calculates the sum of the array's items
pub fn sum(&self, default: Option<Value>, span: Span) -> SourceResult<Value> {
let mut acc = self
.first()
.map(|x| x.clone())
.or_else(|_| {
default.ok_or_else(|| {
eco_format!("cannot calculate sum of empty array with no default")
})
})
.at(span)?;
for i in self.iter().skip(1) {
acc = add(acc, i.clone()).at(span)?;
}
Ok(acc)
}
/// Calculates the product of the array's items
pub fn product(&self, default: Option<Value>, span: Span) -> SourceResult<Value> {
let mut acc = self
.first()
.map(|x| x.clone())
.or_else(|_| {
default.ok_or_else(|| {
eco_format!("cannot calculate product of empty array with no default")
})
})
.at(span)?;
for i in self.iter().skip(1) {
acc = mul(acc, i.clone()).at(span)?;
}
Ok(acc)
}
/// Whether any item matches.
pub fn any(&self, vm: &mut Vm, func: Func) -> SourceResult<bool> {
for item in self.iter() {

View File

@ -105,6 +105,8 @@ pub fn call(
"fold" => {
array.fold(vm, args.expect("initial value")?, args.expect("function")?)?
}
"sum" => array.sum(args.named("default")?, span)?,
"product" => array.product(args.named("default")?, span)?,
"any" => Value::Bool(array.any(vm, args.expect("function")?)?),
"all" => Value::Bool(array.all(vm, args.expect("function")?)?),
"flatten" => Value::Array(array.flatten()),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -166,6 +166,27 @@
// Error: 20-22 unexpected argument
#(1, 2, 3).fold(0, () => none)
---
// Test the `sum` method.
#test(().sum(default: 0), 0)
#test(().sum(default: []), [])
#test((1, 2, 3).sum(), 6)
---
// Error: 2-10 cannot calculate sum of empty array with no default
#().sum()
---
// Test the `product` method.
#test(().product(default: 0), 0)
#test(().product(default: []), [])
#test(([ab], 3).product(), [ab]*3)
#test((1, 2, 3).product(), 6)
---
// Error: 2-14 cannot calculate product of empty array with no default
#().product()
---
// Test the `rev` method.
#test(range(3).rev(), (2, 1, 0))