7 ms·
The Curious Case of JavaScript’s `sort`
- spiderfarmer 11y agoYou should have read W3Schools: > However, if numbers are sorted as strings, "25" is bigger than "100", because "2" is bigger than "1".
- xlm1717 11y agoExactly. If even W3Schools describes the default behavior, it's not exactly a secret.
- andreapaiola 11y agoAh ah nope! You should read MDN The default sort order is according to string Unicode code points. If compareFunction is not supplied, elements are sorted by converting them to strings and comparing strings in Unicode code point order. For example, "Banana" comes before "cherry". In a numeric sort, 9 comes before 80, but because numbers are converted to strings, "80" comes before "9" in Unicode order. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- glitcher 11y agoYet another reason why you shouldn't have read W3 schools.
- Klathmon 11y agoAnd just to throw another wrench in there, because it sorts by Unicode code points, capitals come before lowercase. So this: ['Banana', 'cherry', 'bagel', 'apple'].sort() Will produce this order: ["Banana", "apple", "bagel", "cherry"]
- witty_username 11y agoSo if I'm understanding correctly, JS sort sorts numbers by their string value? That's crazy. And it seems you have to add a compare function just to do a basic operation to sort numbers.
- pjc50 11y agoThis is what happens when people try do to arithmetic in a typeless language. Javascript does not really have a number type; it just has values. Sometimes it infers that you want to do arithmetic on them. What is the correct order of the items ["2", 10, "banana", [[]], "", 1]? See also https://www.destroyallsoftware.com/talks/wat https://www.destroyallsoftware.com/talks/wat Bonus: sometimes you can get the same kind of behaviour in Excel when importing CSV.
- CJefferson 11y agoThe language isn't typeless. Other language (python and ruby, among many others) manage to integer and string comparision correct. It is trickier when someone compares "2" and 3, should we say it's invalid (my preference) or turn 2 into an integer, or 3 into a string? However, there is NO reason for there to be an issue comparing 1 and 11. This is just an unfortunately mistake that is too deeply baked into the language to fix at this point.
- xlm1717 11y agoWhere is the issue comparing 1 and 11? 1 < 11 still returns true. [11,1].sort((a,b) => a -b) still returns [1, 11].
- CJefferson 11y agoSorry, 1 and 11 isn't a problem in javascript. Insert two troublesome numbers :)
- evan_ 11y ago
- CJefferson 11y agoI had some javascript where I wanted to sort a list of list of integers as follows: * Sort each inner list smallest to largest * Sort the list of lists lexicographically It amazed that (a) how stupid javascript's default sort is, and (b) how none of the famous libraries (underscore/lodash) seem to have even fixed the problem of arrays not being compared element-wise, or provide an easy drop-in replacement. EDIT: I replaced the word 'lexicographic' with 'element-wise', as I think it might be causing confusion.
- lotsoflumens 11y agoYes - even Typescript, when arrays are given types, doesn't fix it even though it could be done easily. var x : number[] // should compile: x.sort(function(a,b) { return a - b; }) var y : string[] // should compile: y.sort() The reason that this isn't done is due to a misplaced ideology about "typescript is just javascript" - or some similar nonsense. The bigger problem here is that we are using tools that are designed by a committee, and we have almost no hope of getting this fixed.
- xlm1717 11y agoIt can easily be fixed by passing a sorting function...
- CJefferson 11y agoWell, but then I have to write a comparison function for two arrays of integers. It's not that hard to write, but it took me long enough that I wished the language had it built in (should probably look for it in npm.. if there is left-bad, there must be array-order!)
- akavi 11y agoWhat would "lexicographic" comparison of two arrays mean? As in, what's the canonical string conversion, and how should commas be treated in the ordering? (eg, does `[1,2]` come before or after `[12]` ?) Admittedly, "lexicographic" sorting of numbers is pretty wonky too, but at least there's a pretty canonical string representation of a given number. It seems like a pretty idiosyncratic need without an obvious canonical interpretation, so I'm a little surprised by your surprise at there not being standardish library function for it. Edit: Oh, how embarrassing, I misunderstood the linked post (I thought it was about JS lexicographically sorting integers, rather than arrays of integers). Well, I guess my surprise applies to both you and the author of the link.
- veganman 11y agoNice scroll hijacking /puke
- simlevesque 11y agoStop hijacking my scrollwheel.
- js2 11y agoThe suggestion: function compareNumbers(a, b) { return a - b; } Can this not suffer from overflow/underflow?
- gpvos 11y agoJavascript numbers are reals, not integers. If they become too large (positively or negatively), they become +Infinity or -Infinity.
- hajile 11y agoAll numbers in JS are floats. Overflow and underflow are represented as positive and negative infinity while the check itself looks for 0, greater than zero, less than zero. Both infinities qualify as greater or less than zero (respectively), so I don't believe this problem exists.
- apo 11y agoAlso see: http://blog.rodneyrehm.de/archives/14-Sorting-Were-Doing-It-Wrong.html http://blog.rodneyrehm.de/archives/14-Sorting-Were-Doing-It-...
- meesles 11y agoSounds like your solution would have been to properly read documentation of critical sectors of your code. Assuming that just calling `.sort()` on your arbitrary data would give you exactly what you want was a mistake. Not testing this code was also a mistake, because any combination of different length integers would have shown you this problem very early on, saving you some embarrassment and loss of user trust.
- gpvos 11y agoReally, their testing was inadequate. If your product is a timeline graph, you should test it with data covering a large range across the possible time values. A single date from before roughly 2000 would have uncovered the problem. (Not that I always test adequately, mind you.)
- wscott 11y agoYes yes, everyone one is saying "of course" these are string compares! What a nub mistake. But is it? It is a very easy mistake to make, you pick 'sort' and the resulting code does what you expect. As long as all the timet's have the same number of digits then the string comparison works. You have to have a data that crosses 9/8/2001 to see the problem. (or 3/3/1973 before that) The javascript compiler isn't going to tell you about this and it only hits a problem with dates older than most programs that are written in javascript.
- oldmanjay 11y agoThis behavior has been documented forever, and the broken code written in ignorance of this behavior passed into production because of inadequate testing. Nothing you've said countered these facts.
- fenomas 11y agoCertainly it's an easy mistake to make, but most JS devs tend to encounter it the very first time they call sort() on anything that isn't epoch dates. The fact that the author's code worked for years is a pretty exotic edge case!
- deleted 11y ago[deleted]
- cristiantincu 11y agoSpec: 1. http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.sort http://www.ecma-international.org/ecma-262/6.0/#sec-array.pr... 2. http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare http://www.ecma-international.org/ecma-262/6.0/#sec-sortcomp...
- SimeVidas 11y agoWhy is scrolling so slow in Firefox on that page?
- gpvos 11y agoThey do something to the scroll events on that page. It's pretty terrible.
- Domenic_S 11y agoMySQL exhibits similar behavior if you're comparing numbers stored in a field with string-ish type (eg, varchar): mysql> select cast(123 as char(255)) > "2"; +------------------------------+ | cast(123 as char(255)) > "2" | +------------------------------+ | 0 | +------------------------------+ 1 row in set (0.00 sec) It can really bite you if you're filtering queries on "WHERE char_field > 10". I personally did not think a lot about datatypes after initial table creation... until I ran into this.
- sriram_iyengar 10y agohave seen people raising big uffs-oohs-aahs because of stackoverflow-driven-development :) developer mozilla helps https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... unit tests help !
- gingerrr 10y agoITT: people who expect a language to work just like they want it to instead of reading the docs for the language.