Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,27 @@ Returns the minimum value in the given *iterable* using natural order. If the it

Unlike the built-in [Math.min](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/min), this method ignores undefined, null and NaN values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the minimum of the strings [“20”, “3”] is “20”, while the minimum of the numbers [20, 3] is 3.

See also [scan](#scan) and [extent](#extent).
See also [extent](#extent).

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

Returns the index of the minimum value in the given *iterable* using natural order. If the iterable contains no comparable values, returns -1. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the minimum value.

Unlike the built-in [Math.min](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/min), this method ignores undefined, null and NaN values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the minimum of the strings [“20”, “3”] is “20”, while the minimum of the numbers [20, 3] is 3.

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

Returns the maximum value in the given *iterable* using natural order. If the iterable contains no comparable values, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the maximum value.

Unlike the built-in [Math.max](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/max), this method ignores undefined values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the maximum of the strings [“20”, “3”] is “3”, while the maximum of the numbers [20, 3] is 20.

See also [scan](#scan) and [extent](#extent).
See also [extent](#extent).

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

Returns the index of the maximum value in the given *iterable* using natural order. If the iterable contains no comparable values, returns -1. An optional *accessor* function may be specified, which is equivalent to calling Array.from before computing the maximum value.

Unlike the built-in [Math.max](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/max), this method ignores undefined values; this is useful for ignoring missing data. In addition, elements are compared using natural order rather than numeric order. For example, the maximum of the strings [“20”, “3”] is “3”, while the maximum of the numbers [20, 3] is 20.

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

Expand Down Expand Up @@ -114,17 +126,33 @@ Returns the standard deviation, defined as the square root of the [bias-correcte

Methods for searching arrays for a specific element.

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

Performs a linear scan of the specified *iterable*, returning the index of the least element according to the specified *comparator*. If the given *iterable* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns undefined. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:
Returns the least element of the specified *iterable* according to the specified *comparator*. If the given *iterable* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns undefined. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:

```js
const array = [{foo: 42}, {foo: 91}];
d3.scan(array, (a, b) => a.foo - b.foo); // 0
d3.scan(array, (a, b) => b.foo - a.foo); // 1
d3.least(array, (a, b) => a.foo - b.foo); // {foo: 42}
d3.least(array, (a, b) => b.foo - a.foo); // {foo: 91}
```

This function is similar to [min](#min), except it allows the use of a comparator rather than an accessor and it returns the index instead of the accessed value. See also [bisect](#bisect).
This function is similar to [min](#min), except it allows the use of a comparator rather than an accessor.

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

Returns the index of the least element of the specified *iterable* according to the specified *comparator*. If the given *iterable* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns -1. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:

```js
const array = [{foo: 42}, {foo: 91}];
d3.leastIndex(array, (a, b) => a.foo - b.foo); // 0
d3.leastIndex(array, (a, b) => b.foo - a.foo); // 1
```

This function is similar to [minIndex](#minIndex), except it allows the use of a comparator rather than an accessor.

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

Deprecated; use [leastIndex](#leastIndex) instead.

<a name="bisectLeft" href="#bisectLeft">#</a> d3.<b>bisectLeft</b>(<i>array</i>, <i>x</i>[, <i>lo</i>[, <i>hi</i>]]) · [Source](https://github.com/d3/d3-array/blob/master/src/bisect.js)

Expand Down
10 changes: 5 additions & 5 deletions src/extent.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ export default function(values, valueof) {
let min;
let max;
if (valueof === undefined) {
for (let value of values) {
if (value != null && value >= value) {
for (const value of values) {
if (value != null) {
if (min === undefined) {
min = max = value;
if (value >= value) min = max = value;
} else {
if (min > value) min = value;
if (max < value) max = value;
Expand All @@ -15,9 +15,9 @@ export default function(values, valueof) {
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && value >= value) {
if ((value = valueof(value, ++index, values)) != null) {
if (min === undefined) {
min = max = value;
if (value >= value) min = max = value;
} else {
if (min > value) min = value;
if (max < value) max = value;
Expand Down
8 changes: 6 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,26 @@ export {default as descending} from "./descending.js";
export {default as deviation} from "./deviation.js";
export {default as extent} from "./extent.js";
export {default as group} from "./group.js";
export {default as bin, default as histogram} from "./bin.js";
export {default as bin, default as histogram} from "./bin.js"; // Deprecated; use bin.
export {default as thresholdFreedmanDiaconis} from "./threshold/freedmanDiaconis.js";
export {default as thresholdScott} from "./threshold/scott.js";
export {default as thresholdSturges} from "./threshold/sturges.js";
export {default as max} from "./max.js";
export {default as maxIndex} from "./maxIndex.js";
export {default as mean} from "./mean.js";
export {default as median} from "./median.js";
export {default as merge} from "./merge.js";
export {default as min} from "./min.js";
export {default as minIndex} from "./minIndex.js";
export {default as pairs} from "./pairs.js";
export {default as permute} from "./permute.js";
export {default as quantile} from "./quantile.js";
export {default as quickselect} from "./quickselect.js";
export {default as range} from "./range.js";
export {default as rollup} from "./rollup.js";
export {default as scan} from "./scan.js";
export {default as least} from "./least.js";
export {default as leastIndex} from "./leastIndex.js";
export {default as scan} from "./scan.js"; // Deprecated; use leastIndex.
export {default as shuffle} from "./shuffle.js";
export {default as sum} from "./sum.js";
export {default as ticks, tickIncrement, tickStep} from "./ticks.js";
Expand Down
15 changes: 15 additions & 0 deletions src/least.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ascending from "./ascending.js";

export default function least(values, compare = ascending) {
let min;
let defined = false;
for (const value of values) {
if (defined
? compare(value, min) < 0
: compare(value, value) === 0) {
min = value;
defined = true;
}
}
return min;
}
17 changes: 17 additions & 0 deletions src/leastIndex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ascending from "./ascending.js";

export default function leastIndex(values, compare = ascending) {
let min;
let minIndex = -1;
let index = -1;
for (const value of values) {
++index;
if (minIndex < 0
? compare(value, value) === 0
: compare(value, min) < 0) {
min = value;
minIndex = index;
}
}
return minIndex;
}
8 changes: 3 additions & 5 deletions src/max.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
export default function max(values, valueof) {
let max;
if (valueof === undefined) {
for (let value of values) {
for (const value of values) {
if (value != null
&& value >= value
&& (max === undefined || max < value)) {
&& (max < value || (max === undefined && value >= value))) {
max = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null
&& value >= value
&& (max === undefined || max < value)) {
&& (max < value || (max === undefined && value >= value))) {
max = value;
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/maxIndex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default function maxIndex(values, valueof) {
let max;
let maxIndex = -1;
let index = -1;
if (valueof === undefined) {
for (const value of values) {
++index;
if (value != null
&& (max < value || (max === undefined && value >= value))) {
max = value, maxIndex = index;
}
}
} else {
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null
&& (max < value || (max === undefined && value >= value))) {
max = value, maxIndex = index;
}
}
}
return maxIndex;
}
8 changes: 3 additions & 5 deletions src/min.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
export default function min(values, valueof) {
let min;
if (valueof === undefined) {
for (let value of values) {
for (const value of values) {
if (value != null
&& value >= value
&& (min === undefined || min > value)) {
&& (min > value || (min === undefined && value >= value))) {
min = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null
&& value >= value
&& (min === undefined || min > value)) {
&& (min > value || (min === undefined && value >= value))) {
min = value;
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/minIndex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default function minIndex(values, valueof) {
let min;
let minIndex = -1;
let index = -1;
if (valueof === undefined) {
for (const value of values) {
++index;
if (value != null
&& (min > value || (min === undefined && value >= value))) {
min = value, minIndex = index;
}
}
} else {
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null
&& (min > value || (min === undefined && value >= value))) {
min = value, minIndex = index;
}
}
}
return minIndex;
}
19 changes: 4 additions & 15 deletions src/scan.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
import ascending from "./ascending.js";
import leastIndex from "./leastIndex.js";

export default function scan(values, compare = ascending) {
let min;
let minIndex;
let index = -1;
for (const value of values) {
++index;
if (minIndex === undefined
? compare(value, value) === 0
: compare(value, min) < 0) {
min = value;
minIndex = index;
}
}
return minIndex;
export default function scan(values, compare) {
const index = leastIndex(values, compare);
return index < 0 ? undefined : index;
}
58 changes: 58 additions & 0 deletions test/least-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
var tape = require("tape"),
arrays = require("../");

tape("least(array) compares using natural order", function(test) {
test.strictEqual(arrays.least([0, 1]), 0);
test.strictEqual(arrays.least([1, 0]), 0);
test.strictEqual(arrays.least([0, "1"]), 0);
test.strictEqual(arrays.least(["1", 0]), 0);
test.strictEqual(arrays.least(["10", "2"]), "10");
test.strictEqual(arrays.least(["2", "10"]), "10");
test.strictEqual(arrays.least(["10", "2", NaN]), "10");
test.strictEqual(arrays.least([NaN, "10", "2"]), "10");
test.strictEqual(arrays.least(["2", NaN, "10"]), "10");
test.strictEqual(arrays.least([2, NaN, 10]), 2);
test.strictEqual(arrays.least([10, 2, NaN]), 2);
test.strictEqual(arrays.least([NaN, 10, 2]), 2);
test.end();
});

tape("least(array, compare) compares using the specified compare function", function(test) {
var a = {name: "a"}, b = {name: "b"};
test.deepEqual(arrays.least([a, b], function(a, b) { return a.name.localeCompare(b.name); }), {name: "a"});
test.strictEqual(arrays.least([1, 0], arrays.descending), 1);
test.strictEqual(arrays.least(["1", 0], arrays.descending), "1");
test.strictEqual(arrays.least(["2", "10"], arrays.descending), "2");
test.strictEqual(arrays.least(["2", NaN, "10"], arrays.descending), "2");
test.strictEqual(arrays.least([2, NaN, 10], arrays.descending), 10);
test.end();
});

tape("least(array) returns undefined if the array is empty", function(test) {
test.strictEqual(arrays.least([]), undefined);
test.end();
});

tape("least(array) returns undefined if the array contains only incomparable values", function(test) {
test.strictEqual(arrays.least([NaN, undefined]), undefined);
test.strictEqual(arrays.least([NaN, "foo"], function(a, b) { return a - b; }), undefined);
test.end();
});

tape("least(array) returns the first of equal values", function(test) {
test.deepEqual(arrays.least([2, 2, 1, 1, 0, 0, 0, 3, 0].map(box), ascendingValue), {value: 0, index: 4});
test.deepEqual(arrays.least([3, 2, 2, 1, 1, 0, 0, 0, 3, 0].map(box), descendingValue), {value: 3, index: 0});
test.end();
});

function box(value, index) {
return {value, index};
}

function ascendingValue(a, b) {
return a.value - b.value;
}

function descendingValue(a, b) {
return b.value - a.value;
}
46 changes: 46 additions & 0 deletions test/leastIndex-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
var tape = require("tape"),
arrays = require("../");

tape("leastIndex(array) compares using natural order", function(test) {
test.strictEqual(arrays.leastIndex([0, 1]), 0);
test.strictEqual(arrays.leastIndex([1, 0]), 1);
test.strictEqual(arrays.leastIndex([0, "1"]), 0);
test.strictEqual(arrays.leastIndex(["1", 0]), 1);
test.strictEqual(arrays.leastIndex(["10", "2"]), 0);
test.strictEqual(arrays.leastIndex(["2", "10"]), 1);
test.strictEqual(arrays.leastIndex(["10", "2", NaN]), 0);
test.strictEqual(arrays.leastIndex([NaN, "10", "2"]), 1);
test.strictEqual(arrays.leastIndex(["2", NaN, "10"]), 2);
test.strictEqual(arrays.leastIndex([2, NaN, 10]), 0);
test.strictEqual(arrays.leastIndex([10, 2, NaN]), 1);
test.strictEqual(arrays.leastIndex([NaN, 10, 2]), 2);
test.end();
});

tape("leastIndex(array, compare) compares using the specified compare function", function(test) {
var a = {name: "a"}, b = {name: "b"};
test.strictEqual(arrays.leastIndex([a, b], function(a, b) { return a.name.localeCompare(b.name); }), 0);
test.strictEqual(arrays.leastIndex([1, 0], arrays.descending), 0);
test.strictEqual(arrays.leastIndex(["1", 0], arrays.descending), 0);
test.strictEqual(arrays.leastIndex(["2", "10"], arrays.descending), 0);
test.strictEqual(arrays.leastIndex(["2", NaN, "10"], arrays.descending), 0);
test.strictEqual(arrays.leastIndex([2, NaN, 10], arrays.descending), 2);
test.end();
});

tape("leastIndex(array) returns -1 if the array is empty", function(test) {
test.strictEqual(arrays.leastIndex([]), -1);
test.end();
});

tape("leastIndex(array) returns -1 if the array contains only incomparable values", function(test) {
test.strictEqual(arrays.leastIndex([NaN, undefined]), -1);
test.strictEqual(arrays.leastIndex([NaN, "foo"], function(a, b) { return a - b; }), -1);
test.end();
});

tape("leastIndex(array) returns the first of equal values", function(test) {
test.strictEqual(arrays.leastIndex([2, 2, 1, 1, 0, 0, 0, 3, 0]), 4);
test.strictEqual(arrays.leastIndex([3, 2, 2, 1, 1, 0, 0, 0, 3, 0], arrays.descending), 0);
test.end();
});
Loading