diff --git a/README.md b/README.md index af354e78..e446ded0 100644 --- a/README.md +++ b/README.md @@ -543,7 +543,7 @@ For descending order, negate the group value: d3.groupSort(barley, g => -d3.median(g, d => d.yield), d => d.variety) ``` -If a *comparator* is passed instead of an *accessor* (i.e., if the second argument is a function that takes two arguments), it will be asked to compare two groups *a* and *b* and should return a negative value if *a* should be before *b*, a positive value if *a* should be after *b*, or zero for a partial ordering. +If a *comparator* is passed instead of an *accessor* (i.e., if the second argument is a function that takes exactly two arguments), it will be asked to compare two groups *a* and *b* and should return a negative value if *a* should be before *b*, a positive value if *a* should be after *b*, or zero for a partial ordering. # d3.count(iterable[, accessor]) ยท [Source](https://github.com/d3/d3-array/blob/main/src/count.js), [Examples](https://observablehq.com/@d3/d3-count) @@ -744,7 +744,7 @@ Returns an array containing the values in the given *iterable* in the sorted ord d3.sort(new Set([0, 2, 3, 1])) // [0, 1, 2, 3] ``` -If an *accessor* (a function that takes a single argument) is specified, +If an *accessor* (a function that does not take exactly two arguments) is specified, ```js d3.sort(data, d => d.value) diff --git a/src/bisector.js b/src/bisector.js index 7f80617f..760ceccc 100644 --- a/src/bisector.js +++ b/src/bisector.js @@ -5,7 +5,7 @@ export default function bisector(f) { let compare1 = f; let compare2 = f; - if (f.length === 1) { + if (f.length !== 2) { delta = (d, x) => f(d) - x; compare1 = ascending; compare2 = (d, x) => ascending(f(d), x); diff --git a/src/groupSort.js b/src/groupSort.js index 1d1e93a9..2d56ccf0 100644 --- a/src/groupSort.js +++ b/src/groupSort.js @@ -3,7 +3,7 @@ import group, {rollup} from "./group.js"; import sort from "./sort.js"; export default function groupSort(values, reduce, key) { - return (reduce.length === 1 + return (reduce.length !== 2 ? sort(rollup(values, reduce, key), (([ak, av], [bk, bv]) => ascending(av, bv) || ascending(ak, bk))) : sort(group(values, key), (([ak, av], [bk, bv]) => reduce(av, bv) || ascending(ak, bk)))) .map(([key]) => key); diff --git a/src/rank.js b/src/rank.js index 7c4ebc87..0572e1fa 100644 --- a/src/rank.js +++ b/src/rank.js @@ -5,7 +5,7 @@ export default function rank(values, valueof = ascending) { if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); let V = Array.from(values); const R = new Float64Array(V.length); - if (valueof.length === 1) V = V.map(valueof), valueof = ascending; + if (valueof.length !== 2) V = V.map(valueof), valueof = ascending; const compareIndex = (i, j) => valueof(V[i], V[j]); let k, r; Uint32Array diff --git a/src/sort.js b/src/sort.js index 8d7a41a3..14541beb 100644 --- a/src/sort.js +++ b/src/sort.js @@ -1,10 +1,11 @@ +import ascending from "./ascending.js"; import permute from "./permute.js"; export default function sort(values, ...F) { if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable"); values = Array.from(values); let [f] = F; - if ((f && f.length === 1) || F.length > 1) { + if ((f && f.length !== 2) || F.length > 1) { const index = Uint32Array.from(values, (d, i) => i); if (F.length > 1) { F = F.map(f => values.map(f)); @@ -20,10 +21,11 @@ export default function sort(values, ...F) { } return permute(values, index); } - return values.sort(f === undefined ? ascendingDefined : compareDefined(f)); + return values.sort(compareDefined(f)); } -export function compareDefined(compare) { +export function compareDefined(compare = ascending) { + if (compare === ascending) return ascendingDefined; if (typeof compare !== "function") throw new TypeError("compare is not a function"); return (a, b) => { const x = compare(a, b); diff --git a/test/sort-test.js b/test/sort-test.js index d551fb8c..331dc1e0 100644 --- a/test/sort-test.js +++ b/test/sort-test.js @@ -61,12 +61,12 @@ it("sort(values) accepts an iterable", () => { }); it("sort(values) enforces that values is iterable", () => { - assert.throws(() => sort({}), {name: "TypeError", message: "values is not iterable"}); + assert.throws(() => sort({}), {name: "TypeError", message: /is not iterable/}); }); it("sort(values, comparator) enforces that comparator is a function", () => { - assert.throws(() => sort([], {}), {name: "TypeError", message: "compare is not a function"}); - assert.throws(() => sort([], null), {name: "TypeError", message: "compare is not a function"}); + assert.throws(() => sort([], {}), {name: "TypeError", message: /is not a function/}); + assert.throws(() => sort([], null), {name: "TypeError", message: /is not a function/}); }); it("sort(values) does not skip sparse elements", () => {