UNPKG

3.35 kBPlain TextView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3/*-----------------------------------------------------------------------------
4| Copyright (c) 2014-2017, PhosphorJS Contributors
5|
6| Distributed under the terms of the BSD 3-Clause License.
7|
8| The full license is in the file LICENSE, distributed with this software.
9|----------------------------------------------------------------------------*/
10import { iter, IterableOrArrayLike } from './iter';
11
12/**
13 * Summarize all values in an iterable using a reducer function.
14 *
15 * @param object - The iterable or array-like object of interest.
16 *
17 * @param fn - The reducer function to invoke for each value.
18 *
19 * @param initial - The initial value to start accumulation.
20 *
21 * @returns The final accumulated value.
22 *
23 * #### Notes
24 * The `reduce` function follows the conventions of `Array#reduce`.
25 *
26 * If the iterator is empty, an initial value is required. That value
27 * will be used as the return value. If no initial value is provided,
28 * an error will be thrown.
29 *
30 * If the iterator contains a single item and no initial value is
31 * provided, the single item is used as the return value.
32 *
33 * Otherwise, the reducer is invoked for each element in the iterable.
34 * If an initial value is not provided, the first element will be used
35 * as the initial accumulated value.
36 *
37 * #### Complexity
38 * Linear.
39 *
40 * #### Example
41 * ```typescript
42 * import { reduce } from '@lumino/algorithm';
43 *
44 * let data = [1, 2, 3, 4, 5];
45 *
46 * let sum = reduce(data, (a, value) => a + value); // 15
47 * ```
48 */
49export function reduce<T>(
50 object: IterableOrArrayLike<T>,
51 fn: (accumulator: T, value: T, index: number) => T
52): T;
53export function reduce<T, U>(
54 object: IterableOrArrayLike<T>,
55 fn: (accumulator: U, value: T, index: number) => U,
56 initial: U
57): U;
58export function reduce<T>(
59 object: IterableOrArrayLike<T>,
60 fn: (accumulator: any, value: T, index: number) => any,
61 initial?: any
62): any {
63 // Setup the iterator and fetch the first value.
64 let index = 0;
65 let it = iter(object);
66 let first = it.next();
67
68 // An empty iterator and no initial value is an error.
69 if (first === undefined && initial === undefined) {
70 throw new TypeError('Reduce of empty iterable with no initial value.');
71 }
72
73 // If the iterator is empty, return the initial value.
74 if (first === undefined) {
75 return initial;
76 }
77
78 // If the iterator has a single item and no initial value, the
79 // reducer is not invoked and the first item is the return value.
80 let second = it.next();
81 if (second === undefined && initial === undefined) {
82 return first;
83 }
84
85 // If iterator has a single item and an initial value is provided,
86 // the reducer is invoked and that result is the return value.
87 if (second === undefined) {
88 return fn(initial, first, index++);
89 }
90
91 // Setup the initial accumlated value.
92 let accumulator: any;
93 if (initial === undefined) {
94 accumulator = fn(first, second, index++);
95 } else {
96 accumulator = fn(fn(initial, first, index++), second, index++);
97 }
98
99 // Iterate the rest of the values, updating the accumulator.
100 let next: T | undefined;
101 while ((next = it.next()) !== undefined) {
102 accumulator = fn(accumulator, next, index++);
103 }
104
105 // Return the final accumulated value.
106 return accumulator;
107}