diff --git a/README.md b/README.md index 2e34072e..72443fcd 100644 --- a/README.md +++ b/README.md @@ -127,25 +127,29 @@ Returns the standard deviation, defined as the square root of the [bias-correcte Methods for searching arrays for a specific element. # d3.least(iterable[, comparator]) · [Source](https://github.com/d3/d3-array/blob/master/src/least.js), [Examples](https://observablehq.com/@d3/d3-least) +
# d3.least(iterable[, accessor]) -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: +Returns the least element of the specified *iterable* according to the specified *comparator* or *accessor*. 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.least(array, (a, b) => a.foo - b.foo); // {foo: 42} d3.least(array, (a, b) => b.foo - a.foo); // {foo: 91} +d3.least(array, a => a.foo); // {foo: 42} ``` This function is similar to [min](#min), except it allows the use of a comparator rather than an accessor. # d3.leastIndex(iterable[, comparator]) · [Source](https://github.com/d3/d3-array/blob/master/src/leastIndex.js), [Examples](https://observablehq.com/@d3/d3-least) +
# d3.leastIndex(iterable[, comparator]) -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: +Returns the index of the least element of the specified *iterable* according to the specified *comparator* or *accessor*. 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 +d3.leastIndex(array, a => a.foo); // 0 ``` This function is similar to [minIndex](#minIndex), except it allows the use of a comparator rather than an accessor. diff --git a/src/least.js b/src/least.js index 53d470bc..a756abf4 100644 --- a/src/least.js +++ b/src/least.js @@ -3,12 +3,26 @@ 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; + if (compare.length === 1) { + let minValue; + for (const element of values) { + const value = compare(element); + if (defined + ? ascending(value, minValue) < 0 + : ascending(value, value) === 0) { + min = element; + minValue = value; + defined = true; + } + } + } else { + for (const value of values) { + if (defined + ? compare(value, min) < 0 + : compare(value, value) === 0) { + min = value; + defined = true; + } } } return min; diff --git a/src/leastIndex.js b/src/leastIndex.js index 3abf9058..2cd7a931 100644 --- a/src/leastIndex.js +++ b/src/leastIndex.js @@ -4,13 +4,26 @@ 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; + if (compare.length === 1) { + for (const element of values) { + ++index; + const value = compare(element); + if (minIndex < 0 + ? ascending(value, value) === 0 + : ascending(value, min) < 0) { + min = value; + minIndex = index; + } + } + } else { + for (const value of values) { + ++index; + if (minIndex < 0 + ? compare(value, value) === 0 + : compare(value, min) < 0) { + min = value; + minIndex = index; + } } } return minIndex; diff --git a/test/least-test.js b/test/least-test.js index 531c78b7..34407df5 100644 --- a/test/least-test.js +++ b/test/least-test.js @@ -28,6 +28,13 @@ tape("least(array, compare) compares using the specified compare function", func test.end(); }); +tape("least(array, accessor) uses the specified accessor function", function(test) { + var a = {name: "a", v: 42}, b = {name: "b", v: 0.42}; + test.deepEqual(arrays.least([a, b], d => d.name), a); + test.deepEqual(arrays.least([a, b], d => d.v), b); + test.end(); +}); + tape("least(array) returns undefined if the array is empty", function(test) { test.strictEqual(arrays.least([]), undefined); test.end(); diff --git a/test/leastIndex-test.js b/test/leastIndex-test.js index 472fcb03..407cb606 100644 --- a/test/leastIndex-test.js +++ b/test/leastIndex-test.js @@ -28,6 +28,13 @@ tape("leastIndex(array, compare) compares using the specified compare function", test.end(); }); +tape("leastIndex(array, accessor) uses the specified accessor function", function(test) { + var a = {name: "a", v: 42}, b = {name: "b", v: 0.42}; + test.deepEqual(arrays.leastIndex([a, b], d => d.name), 0); + test.deepEqual(arrays.leastIndex([a, b], d => d.v), 1); + test.end(); +}); + tape("leastIndex(array) returns -1 if the array is empty", function(test) { test.strictEqual(arrays.leastIndex([]), -1); test.end();