diff --git a/collections/README.md b/collections/README.md index 8bc2fd9b7fd1..5ac6fcce5bbf 100644 --- a/collections/README.md +++ b/collections/README.md @@ -834,3 +834,21 @@ const random = sample(numbers); assert(numbers.includes(random as number)); ``` + +### runningReduce + +Calls the given reducer on each element of the given collection, passing it's +result as the accumulator to the next respective call, starting with the given +initialValue. Returns all intermediate accumulator results. + +Example: + +```ts +import { runningReduce } from "https://deno.land/std@$STD_VERSION/collections/mod.ts"; +import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + +const numbers = [1, 2, 3, 4, 5]; +const sumSteps = runningReduce(numbers, (sum, current) => sum + current, 0); + +assertEquals(sumSteps, [1, 3, 6, 10, 15]); +``` diff --git a/collections/mod.ts b/collections/mod.ts index 0e6acbdc8f30..e1cc1cdf7d98 100644 --- a/collections/mod.ts +++ b/collections/mod.ts @@ -41,3 +41,4 @@ export * from "./first_not_nullish_of.ts"; export * from "./drop_last_while.ts"; export * from "./reduce_groups.ts"; export * from "./sample.ts"; +export * from "./running_reduce.ts"; diff --git a/collections/running_reduce.ts b/collections/running_reduce.ts new file mode 100644 index 000000000000..24995dee2049 --- /dev/null +++ b/collections/running_reduce.ts @@ -0,0 +1,27 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +/** + * Calls the given reducer on each element of the given collection, passing it's + * result as the accumulator to the next respective call, starting with the given + * initialValue. Returns all intermediate accumulator results. + * + * Example: + * + * ```ts + * import { runningReduce } from "https://deno.land/std@$STD_VERSION/collections/mod.ts"; + * import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * const numbers = [1, 2, 3, 4, 5]; + * const sumSteps = runningReduce(numbers, (sum, current) => sum + current, 0); + * + * assertEquals(sumSteps, [1, 3, 6, 10, 15]); + * ``` + */ +export function runningReduce( + array: readonly T[], + reducer: (accumulator: O, current: T) => O, + initialValue: O, +): O[] { + let currentResult = initialValue; + return array.map((el) => currentResult = reducer(currentResult, el)); +} diff --git a/collections/running_reduce_test.ts b/collections/running_reduce_test.ts new file mode 100644 index 000000000000..1c9550981b28 --- /dev/null +++ b/collections/running_reduce_test.ts @@ -0,0 +1,43 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +import { assertEquals } from "../testing/asserts.ts"; +import { runningReduce } from "./running_reduce.ts"; + +Deno.test({ + name: "[collections/runningReduce] no mutation", + fn() { + const numbers = [1, 2, 3, 4, 5]; + runningReduce(numbers, (sum, current) => sum + current, 0); + + assertEquals(numbers, [1, 2, 3, 4, 5]); + }, +}); + +Deno.test({ + name: "[collections/runningReduce] array of numbers", + fn() { + const numbers = [1, 2, 3, 4, 5]; + const result = runningReduce(numbers, (sum, current) => sum + current, 0); + + assertEquals(result, [1, 3, 6, 10, 15]); + }, +}); + +Deno.test({ + name: "[collections/runningReduce] array of strings", + fn() { + const strings = ["a", "b", "c", "d", "e"]; + const result = runningReduce(strings, (str, current) => str + current, ""); + + assertEquals(result, ["a", "ab", "abc", "abcd", "abcde"]); + }, +}); + +Deno.test({ + name: "[collections/runningReduce] empty input", + fn() { + const result = runningReduce([], (sum, current) => sum + current, 0); + + assertEquals(result, []); + }, +});