Skip to content

groupSort: use ascendingDefined - #285

Open
cpruijsen wants to merge 1 commit into
d3:mainfrom
cpruijsen:fix/issue-273
Open

cpruijsen wants to merge 1 commit into
d3:mainfrom
cpruijsen:fix/issue-273

Conversation

@cpruijsen

Copy link
Copy Markdown

Fixes #273.

ascending returns NaN when either side is null or NaN, and NaN is falsy, so the comparator in
src/groupSort.js

([ak, av], [bk, bv]) => ascending(av, bv) || ascending(ak, bk)

fell through to the key comparison whenever a reduced value was non-orderable, instead of ranking
that group. So a group whose reduced value is null sorted by key among the real values rather than
last:

groupSort([{key: "z", value: 2}, {key: "a", value: null}, {key: "m", value: 1}],
          g => g[0].value, d => d.key)
// ["a", "m", "z"]   the null ordered by its key
// ["m", "z", "a"]   with this change

ascendingDefined returns 1 or -1 rather than NaN there, so the || no longer swallows the
result.

The key comparison is switched too, and that half is not a behaviour change. The issue asks for
both, so both are here, but it is worth being exact about which one fixes something. sort passes
any length-2 comparator through compareDefined, whose fallback

return (compare(b, b) === 0) - (compare(a, a) === 0);

already ranks a NaN result last, so keys were ordered correctly through the wrapper. I checked
null, undefined and NaN keys against numeric and string keys, and the output is identical before and
after. Switching it makes the comparator correct on its own rather than by rescue, which is what
makes the two halves read the same way.

One test, on the half that changes. I dropped a second test I had written for the key path: it
passed against main as well, so it documented existing behaviour while looking like coverage of
this change.

mocha 'test/**/*-test.js' is 530 passing, 1 pending, and eslint src test is clean, both on Node
20.20.2 (mocha 8's CLI does not start on Node 26).

ascending returns NaN when either side is null or NaN, and NaN is falsy,
so `ascending(av, bv) || ascending(ak, bk)` fell through to the key
comparison instead of ranking the non-orderable value. A group whose
reduced value is null sorted by key among the real values rather than
last: [z:2, a:null, m:1] gave [a, m, z] rather than [m, z, a].

ascendingDefined returns 1 or -1 there, so the || no longer swallows it.

The key comparison is switched too, as the issue asks. That one is not a
behaviour change: sort wraps any comparator in compareDefined, whose
fallback already ranks a NaN result last, so keys were ordered correctly
through the wrapper. It is switched so the comparator is right on its own
rather than by rescue.

Fixes d3#273
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

groupSort should use ascendingDefined instead of ascending

1 participant