Skip to content

Commit

Permalink
Add d3.cross. Fixes #50.
Browse files Browse the repository at this point in the history
For consistency, d3.pairs now takes an optional reducer.
  • Loading branch information
mbostock committed Feb 28, 2017
1 parent 94e197a commit c57a084
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 4 deletions.
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,23 @@ Note that if no comparator function is specified to the built-in sort method, th

Methods for transforming arrays and for generating new arrays.

<a name="cross" href="#cross">#</a> d3.<b>cross</b>(<i>a</i>, <i>b</i>[, <i>reducer</i>]) [<>](https://github.com/d3/d3-array/blob/master/src/cross.js "Source")

Returns the [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product) of the two arrays *a* and *b*. For each element *i* in the specified array *a* and each element *j* in the specified array *b*, in order, invokes the specified *reducer* function passing the element *i* and element *j*. If a *reducer* is not specified, it defaults to a function which creates a two-element array for each pair:

```js
function pair(a, b) {
return [a, b];
}
```

For example:

```js
d3.cross([1, 2], ["x", "y"]); // returns [[1, "x"], [1, "y"], [2, "x"], [2, "y"]]
d3.cross([1, 2], ["x", "y"], (a, b) => a + b); // returns ["1x", "1y", "2x", "2y"]
```

<a name="merge" href="#merge">#</a> d3.<b>merge</b>(<i>arrays</i>) [<>](https://github.com/d3/d3-array/blob/master/src/merge.js "Source")

Merges the specified *arrays* into a single array. This method is similar to the built-in array concat method; the only difference is that it is more convenient when you have an array of arrays.
Expand All @@ -210,12 +227,21 @@ Merges the specified *arrays* into a single array. This method is similar to the
d3.merge([[1], [2, 3]]); // returns [1, 2, 3]
```

<a name="pairs" href="#pairs">#</a> d3.<b>pairs</b>(<i>array</i>) [<>](https://github.com/d3/d3-array/blob/master/src/pairs.js "Source")
<a name="pairs" href="#pairs">#</a> d3.<b>pairs</b>(<i>array</i>[, <i>reducer</i>]) [<>](https://github.com/d3/d3-array/blob/master/src/pairs.js "Source")

For each adjacent pair of elements in the specified *array*, in order, invokes the specified *reducer* function passing the element *i* and element *i* - 1. If a *reducer* is not specified, it defaults to a function which creates a two-element array for each pair:

```js
function pair(a, b) {
return [a, b];
}
```

For each adjacent pair of elements in the specified *array*, returns a new array of tuples of element *i* and element *i* - 1. For example:
For example:

```js
d3.pairs([1, 2, 3, 4]); // returns [[1, 2], [2, 3], [3, 4]]
d3.pairs([1, 2, 3, 4], (a, b) => b - a); // returns [1, 1, 1];
```

If the specified array has fewer than two elements, returns the empty array.
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export {default as bisect, bisectRight, bisectLeft} from "./src/bisect";
export {default as ascending} from "./src/ascending";
export {default as bisector} from "./src/bisector";
export {default as cross} from "./src/cross";
export {default as descending} from "./src/descending";
export {default as deviation} from "./src/deviation";
export {default as extent} from "./src/extent";
Expand Down
8 changes: 8 additions & 0 deletions src/cross.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {pair} from "./pairs";

export default function(a, b, f) {
var na = a.length, nb = b.length, c = new Array(na * nb), ia, ib, ic, va;
if (f == null) f = pair;
for (ia = ic = 0; ia < na; ++ia) for (va = a[ia], ib = 0; ib < nb; ++ib, ++ic) c[ic] = f(va, b[ib]);
return c;
}
9 changes: 7 additions & 2 deletions src/pairs.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export default function(array) {
export default function(array, f) {
if (f == null) f = pair;
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
while (i < n) pairs[i] = [p, p = array[++i]];
while (i < n) pairs[i] = f(p, p = array[++i]);
return pairs;
}

export function pair(a, b) {
return [a, b];
}
12 changes: 12 additions & 0 deletions test/cross-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var tape = require("tape"),
arrays = require("../");

tape("cross(a, b) returns Cartesian product a×b", function(test) {
test.deepEqual(arrays.cross([1, 2], ["x", "y"]), [[1, "x"], [1, "y"], [2, "x"], [2, "y"]]);
test.end();
});

tape("cross(a, b, f) invokes the specified function for each pair", function(test) {
test.deepEqual(arrays.cross([1, 2], ["x", "y"], (a, b) => a + b), ["1x", "1y", "2x", "2y"]);
test.end();
});
5 changes: 5 additions & 0 deletions test/pairs-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ tape("pairs(array) returns pairs of adjacent elements in the given array", funct
test.end();
});

tape("pairs(array, f) invokes the function f for each pair of adjacent elements", function(test) {
test.deepEqual(arrays.pairs([1, 3, 7], (a, b) => b - a), [2, 4]);
test.end();
});

tape("pairs(array) includes null or undefined elements in pairs", function(test) {
test.deepEqual(arrays.pairs([1, null, 2]), [[1, null], [null, 2]]);
test.deepEqual(arrays.pairs([1, 2, undefined]), [[1, 2], [2, undefined]]);
Expand Down

0 comments on commit c57a084

Please sign in to comment.