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..db7944f5 100644
--- a/src/least.js
+++ b/src/least.js
@@ -1,14 +1,28 @@
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;
+export default function least(values, f = ascending) {
+ const valueof = f.length === 1 ? f : undefined,
+ compare = f.length === 2 ? f : ascending;
+ let min, minv, v, defined = false;
+ if (valueof === undefined) {
+ for (const value of values) {
+ if (defined
+ ? compare(value, min) < 0
+ : compare(value, value) === 0) {
+ min = value;
+ defined = true;
+ }
+ }
+ } else {
+ for (const value of values) {
+ v = valueof(value);
+ if (defined
+ ? compare(v, minv) < 0
+ : compare(v, v) === 0) {
+ min = value;
+ minv = v;
+ defined = true;
+ }
}
}
return min;
diff --git a/src/leastIndex.js b/src/leastIndex.js
index 3abf9058..6a2b8f24 100644
--- a/src/leastIndex.js
+++ b/src/leastIndex.js
@@ -1,16 +1,31 @@
import ascending from "./ascending.js";
-export default function leastIndex(values, compare = ascending) {
- let min;
+export default function leastIndex(values, f = ascending) {
+ const valueof = f.length === 1 ? f : undefined,
+ compare = f.length === 2 ? f : ascending;
+ let min, v;
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 (valueof === undefined) {
+ for (const value of values) {
+ ++index;
+ if (minIndex < 0
+ ? compare(value, value) === 0
+ : compare(value, min) < 0) {
+ min = value;
+ minIndex = index;
+ }
+ }
+ } else {
+ for (const value of values) {
+ ++index;
+ v = valueof(value);
+ if (minIndex < 0
+ ? compare(v, v) === 0
+ : compare(v, min) < 0) {
+ min = v;
+ 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();