Search code examples
javascriptecmascript-intl

Intl.Collator and natural sort with numeric option sorts incorrectly with decimal numbers


Sorting decimal numbers using Intl.Collator and the option to enable numeric compares decimals incorrectly.

On some browsers comparing "0.005" and "0.05" returns "0" as in the numbers are the same.

Results in different browsers:

  • Chrome 54 = 0
  • Firefox 49 = 0
  • Edge = -1
  • IE 11 = -1

// Returns 0
console.log(new Intl.Collator(undefined, { numeric: true}).compare(0.000005, 0.05))

Anyone that can tell me whats wrong?

Reported as bug in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1312388


Solution

  • As André Bargull observes in the Firefox bug report, numeric sorting considers only decimal digit sequences, i.e. in the Unicode category of Number, by their numeric values. That is, when comparing two otherwise-identical strings containing decimal numbers with fractional components, the entire decimal numbers aren't considered for their numeric value -- because U+002E FULL STOP isn't in the Number category (it's instead in the Punctuation category).

    So then, when we compare these two strings -- "0.05" and "0.000005" -- we effectively are comparing these arrays of elements:

    ["0", ".", "05"]
    ["0", ".", "000005"]
    

    and then when digit sequences are considered by their numeric values, we're comparing

    [0, ".", 5]
    [0, ".", 5]
    

    which are equal, and so compare should return 0 when comparing them. Firefox and Chrome are right here, and IE and Edge are mistaken.