From 82da2dcc8bef86cf590cb5d8fd5e7bfd483a1959 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 2 Oct 2021 10:56:20 -0700 Subject: [PATCH 1/7] only comparator if function.length === 2 --- src/rank.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 3144029e33d59174c655782931cd56009892bcee Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 2 Oct 2021 10:57:10 -0700 Subject: [PATCH 2/7] only comparator if function.length === 2 --- src/bisector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From bb71f8b166912d4f36999b91a1180eb18b9d27d5 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 2 Oct 2021 10:57:34 -0700 Subject: [PATCH 3/7] only comparator if function.length === 2 --- src/groupSort.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From 8ee869b44b30f9d697072c361338cb2ada8c7498 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 2 Oct 2021 10:58:56 -0700 Subject: [PATCH 4/7] only comparator if function.length === 2 --- src/sort.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sort.js b/src/sort.js index 8d7a41a3..b68f89fb 100644 --- a/src/sort.js +++ b/src/sort.js @@ -4,7 +4,7 @@ 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 +20,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); From 7ee96cb6e6e78054d23964104cbb317b5d35176b Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 2 Oct 2021 11:01:13 -0700 Subject: [PATCH 5/7] import ascending --- src/sort.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sort.js b/src/sort.js index b68f89fb..14541beb 100644 --- a/src/sort.js +++ b/src/sort.js @@ -1,3 +1,4 @@ +import ascending from "./ascending.js"; import permute from "./permute.js"; export default function sort(values, ...F) { From 1ce887ff01a110802ae26918bba46322826f8909 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 2 Oct 2021 11:05:21 -0700 Subject: [PATCH 6/7] relax error message test --- test/sort-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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", () => { From 4c90f3317a2a046d3ade1cdfcd030001f8e77799 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 2 Oct 2021 11:09:14 -0700 Subject: [PATCH 7/7] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)