Skip to content

Commit ce9507c

Browse files
authored
Merge pull request #126 from d3/cumsum
cumsum
2 parents 8008dd8 + d137d27 commit ce9507c

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ Returns the mean of the given *iterable* of numbers. If the iterable contains no
9898

9999
Returns the median of the given *iterable* of numbers using the [R-7 method](https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample). If the iterable contains no numbers, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the median. This method ignores undefined and NaN values; this is useful for ignoring missing data.
100100

101+
<a name="cumsum" href="#cumsum">#</a> d3.<b>cumsum</b>(<i>iterable</i>[, <i>accessor</i>]) · [Source](https://github.com/d3/d3-array/blob/master/src/cumsum.js), [Examples](https://observablehq.com/@d3/d3-cumsum)
102+
103+
Returns the cumulative sum of the given *iterable* of numbers, as a Float64Array of the same length. If the iterable contains no numbers, returns zeros. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the cumulative sum. This method ignores undefined and NaN values; this is useful for ignoring missing data.
104+
101105
<a name="quantile" href="#quantile">#</a> d3.<b>quantile</b>(<i>iterable</i>, <i>p</i>[, <i>accessor</i>]) · [Source](https://github.com/d3/d3-array/blob/master/src/quantile.js), [Examples](https://observablehq.com/@d3/d3-mean-d3-median-and-friends)
102106

103107
Returns the *p*-quantile of the given *iterable* of numbers, where *p* is a number in the range [0, 1]. For example, the median can be computed using *p* = 0.5, the first quartile at *p* = 0.25, and the third quartile at *p* = 0.75. This particular implementation uses the [R-7 method](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population), which is the default for the R programming language and Excel. For example:

src/cumsum.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default function cumsum(values, valueof) {
2+
var sum = 0, index = 0;
3+
return Float64Array.from(values, valueof === undefined
4+
? v => (sum += +v || 0)
5+
: v => (sum += +valueof(v, index++, values) || 0));
6+
}

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export {default as ascending} from "./ascending.js";
33
export {default as bisector} from "./bisector.js";
44
export {default as count} from "./count.js";
55
export {default as cross} from "./cross.js";
6+
export {default as cumsum} from "./cumsum.js";
67
export {default as descending} from "./descending.js";
78
export {default as deviation} from "./deviation.js";
89
export {default as extent} from "./extent.js";

test/cumsum-test.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
var tape = require("tape"),
2+
arrays = require("../");
3+
4+
tape("cumsum(array) returns the cumulative sum of the specified numbers", function(test) {
5+
test.deepEqual(arrays.cumsum([1]), [1]);
6+
test.deepEqual(arrays.cumsum([5, 1, 2, 3, 4]), [5, 6, 8, 11, 15]);
7+
test.deepEqual(arrays.cumsum([20, 3]), [20, 23]);
8+
test.deepEqual(arrays.cumsum([3, 20]), [3, 23]);
9+
test.end();
10+
});
11+
12+
tape("cumsum(array) observes values that can be coerced to numbers", function(test) {
13+
test.deepEqual(arrays.cumsum(["20", "3"]), [20, 23]);
14+
test.deepEqual(arrays.cumsum(["3", "20"]), [3, 23]);
15+
test.deepEqual(arrays.cumsum(["3", 20]), [3, 23]);
16+
test.deepEqual(arrays.cumsum([20, "3"]), [20, 23]);
17+
test.deepEqual(arrays.cumsum([3, "20"]), [3, 23]);
18+
test.deepEqual(arrays.cumsum(["20", 3]), [20, 23]);
19+
test.end();
20+
});
21+
22+
tape("cumsum(array) ignores non-numeric values", function(test) {
23+
test.deepEqual(arrays.cumsum(["a", "b", "c"]), [0, 0, 0]);
24+
test.deepEqual(arrays.cumsum(["a", 1, "2"]), [0, 1, 3]);
25+
test.end();
26+
});
27+
28+
tape("cumsum(array) ignores null, undefined and NaN", function(test) {
29+
test.deepEqual(arrays.cumsum([NaN, 1, 2, 3, 4, 5]), [0, 1, 3, 6, 10, 15]);
30+
test.deepEqual(arrays.cumsum([1, 2, 3, 4, 5, NaN]), [1, 3, 6, 10, 15, 15]);
31+
test.deepEqual(arrays.cumsum([10, null, 3, undefined, 5, NaN]), [10, 10, 13, 13, 18, 18]);
32+
test.end();
33+
});
34+
35+
tape("cumsum(array) returns zeros if there are no numbers", function(test) {
36+
test.deepEqual(arrays.cumsum([]), []);
37+
test.deepEqual(arrays.cumsum([NaN]), [0]);
38+
test.deepEqual(arrays.cumsum([undefined]), [0]);
39+
test.deepEqual(arrays.cumsum([undefined, NaN]), [0, 0]);
40+
test.deepEqual(arrays.cumsum([undefined, NaN, {}]), [0, 0, 0]);
41+
test.end();
42+
});
43+
44+
tape("cumsum(array, f) returns the cumsum of the specified numbers", function(test) {
45+
test.deepEqual(arrays.cumsum([1].map(box), unbox), [1]);
46+
test.deepEqual(arrays.cumsum([5, 1, 2, 3, 4].map(box), unbox), [5, 6, 8, 11, 15]);
47+
test.deepEqual(arrays.cumsum([20, 3].map(box), unbox), [20, 23]);
48+
test.deepEqual(arrays.cumsum([3, 20].map(box), unbox), [3, 23]);
49+
test.end();
50+
});
51+
52+
tape("cumsum(array, f) observes values that can be coerced to numbers", function(test) {
53+
test.deepEqual(arrays.cumsum(["20", "3"].map(box), unbox), [20, 23]);
54+
test.deepEqual(arrays.cumsum(["3", "20"].map(box), unbox), [3, 23]);
55+
test.deepEqual(arrays.cumsum(["3", 20].map(box), unbox), [3, 23]);
56+
test.deepEqual(arrays.cumsum([20, "3"].map(box), unbox), [20, 23]);
57+
test.deepEqual(arrays.cumsum([3, "20"].map(box), unbox), [3, 23]);
58+
test.deepEqual(arrays.cumsum(["20", 3].map(box), unbox), [20, 23]);
59+
test.end();
60+
});
61+
62+
tape("cumsum(array, f) ignores non-numeric values", function(test) {
63+
test.deepEqual(arrays.cumsum(["a", "b", "c"].map(box), unbox), [0, 0, 0]);
64+
test.deepEqual(arrays.cumsum(["a", 1, "2"].map(box), unbox), [0, 1, 3]);
65+
test.end();
66+
});
67+
68+
tape("cumsum(array, f) ignores null, undefined and NaN", function(test) {
69+
test.deepEqual(arrays.cumsum([NaN, 1, 2, 3, 4, 5].map(box), unbox), [0, 1, 3, 6, 10, 15]);
70+
test.deepEqual(arrays.cumsum([1, 2, 3, 4, 5, NaN].map(box), unbox), [1, 3, 6, 10, 15, 15]);
71+
test.deepEqual(arrays.cumsum([10, null, 3, undefined, 5, NaN].map(box), unbox), [10, 10, 13, 13, 18, 18]);
72+
test.end();
73+
});
74+
75+
tape("cumsum(array, f) returns zeros if there are no numbers", function(test) {
76+
test.deepEqual(arrays.cumsum([].map(box), unbox), []);
77+
test.deepEqual(arrays.cumsum([NaN].map(box), unbox), [0]);
78+
test.deepEqual(arrays.cumsum([undefined].map(box), unbox), [0]);
79+
test.deepEqual(arrays.cumsum([undefined, NaN].map(box), unbox), [0, 0]);
80+
test.deepEqual(arrays.cumsum([undefined, NaN, {}].map(box), unbox), [0, 0, 0]);
81+
test.end();
82+
});
83+
84+
tape("cumsum(array, f) passes the accessor d, i, and array", function(test) {
85+
var results = [], array = ["a", "b", "c"];
86+
arrays.cumsum(array, function(d, i, array) { results.push([d, i, array]); });
87+
test.deepEqual(results, [["a", 0, array], ["b", 1, array], ["c", 2, array]]);
88+
test.end();
89+
});
90+
91+
tape("cumsum(array, f) uses the global context", function(test) {
92+
var results = [];
93+
arrays.cumsum([1, 2], function() { results.push(this); });
94+
test.deepEqual(results, [global, global]);
95+
test.end();
96+
});
97+
98+
function box(value) {
99+
return {value: value};
100+
}
101+
102+
function unbox(box) {
103+
return box.value;
104+
}

0 commit comments

Comments
 (0)