summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustForFun88 <100504524+JustForFun88@users.noreply.github.com>2024-04-30 17:21:40 +0500
committerGitHub <noreply@github.com>2024-04-30 12:21:40 +0000
commitd7838ab1288672a67fc746a89eb6a04c7ed8c8cf (patch)
treece879cb638093f01a6741392b5b253f36773d83e
parent97de0a0595d28e29d944112ab6e06700d9c9d73d (diff)
Add `reduce` method to `array` (#3911)
-rw-r--r--crates/typst/src/foundations/array.rs30
-rw-r--r--tests/suite/foundations/array.typ13
2 files changed, 43 insertions, 0 deletions
diff --git a/crates/typst/src/foundations/array.rs b/crates/typst/src/foundations/array.rs
index 7d76cf5b..6bde7d6c 100644
--- a/crates/typst/src/foundations/array.rs
+++ b/crates/typst/src/foundations/array.rs
@@ -882,6 +882,36 @@ impl Array {
})
.collect()
}
+
+ /// Reduces the elements to a single one, by repeatedly applying a reducing
+ /// operation.
+ ///
+ /// If the array is empty, returns `none`, otherwise, returns the
+ /// result of the reduction.
+ ///
+ /// The reducing function is a closure with two arguments: an 'accumulator', and an element.
+ ///
+ /// For arrays with at least one element, this is the same as `array.fold`
+ /// with the first element of the array as the initial accumulator value, folding
+ /// every subsequent element into it.
+ #[func]
+ pub fn reduce(
+ self,
+ /// The engine.
+ engine: &mut Engine,
+ /// The callsite context.
+ context: Tracked<Context>,
+ /// The reducing function. Must have two parameters: One for the
+ /// accumulated value and one for an item.
+ reducer: Func,
+ ) -> SourceResult<Value> {
+ let mut iter = self.into_iter();
+ let mut acc = iter.next().unwrap_or_default();
+ for item in iter {
+ acc = reducer.call(engine, context, [acc, item])?;
+ }
+ Ok(acc)
+ }
}
/// A value that can be cast to bytes.
diff --git a/tests/suite/foundations/array.typ b/tests/suite/foundations/array.typ
index 3992d75e..336c5a67 100644
--- a/tests/suite/foundations/array.typ
+++ b/tests/suite/foundations/array.typ
@@ -492,3 +492,16 @@
--- array-unclosed ---
// Error: 3-4 unclosed delimiter
#{(}
+
+--- array-reduce ---
+// Test the `reduce` method.
+#test(().reduce(grid), none)
+#test((1, 2, 3, 4).reduce((s, x) => s + x), 10)
+
+--- array-reduce-missing-reducer ---
+// Error: 2-13 missing argument: reducer
+#().reduce()
+
+--- array-reduce-unexpected-argument ---
+// Error: 19-21 unexpected argument
+#(1, 2, 3).reduce(() => none) \ No newline at end of file