20

This simple javascript

var x = new Array();
x[0] = 2.73;
x[1] = 11.17;
x[2] = 3.12
x.sort();

for(var i in x)
    alert(x[i]);

produces the results: 11.17, 2.73, 3.12 instead of 2.73, 3.12, 11.17.

Why is that and how can I fix it?

Thanks in advance!

Zarel
  • 2,201
  • 1
  • 15
  • 20
Christos Mitsis
  • 323
  • 2
  • 6
  • 15

5 Answers5

25

It's sorting alphabetically, try passing your own sorting function:

var x = new Array();
x[0] = 2.73;
x[1] = 11.17;
x[2] = 3.12;

numberSort = function (a,b) {
    return a - b;
};

x.sort(numberSort);

for(var i in x) {
    alert(x[i]);
}
Tom
  • 43,583
  • 4
  • 41
  • 61
  • 1
    Please note that this method will not work if you have inifite or NaN values - in this case you will either need to .filter() your NaN values, or use more sophisticated comparator logic as here: https://stackoverflow.com/a/17557983/3646777 – Jack Feb 09 '21 at 22:02
11

By default, Array.sort will sort alphabetically (lexographically)...but you can supply your own function. Try:

x.sort(function(a, b) { return a > b ? 1 : -1});
sje397
  • 41,293
  • 8
  • 87
  • 103
  • 5
    One can also write `return a-b`, since only the sign of the returned value matters. – Max May 23 '11 at 07:04
  • @Max: sounds like a good idea. Is that safe in all browsers that have `Array.sort`? – sje397 May 23 '11 at 07:05
  • 1
    @sje397: Yes, that's safe. It's defined that way in the ECMAScript spec and all major browsers work that way. – Tim Down May 23 '11 at 08:53
  • 2
    @sje397: Well, I say that, but actually it isn't entirely safe: if `a - b` returns a number greater than `Number.MAX_VALUE` or less than `-Number.MAX_VALUE` then it could break. Something of an edge case though. – Tim Down May 23 '11 at 10:59
  • @Tim: details, details :) Safer to stick with the ternary then probably. They're endangered anyway. – sje397 May 23 '11 at 11:01
  • **ES6:** `[1,2].sort((a,b)=> a-b)` – vsync Mar 20 '16 at 09:05
5

Array.sort() function treats its elements as Strings and if no function is passed to the sort() statement, it converts the elements to Unicode and sorts. Therefore, it is advised to pass a custom sort Function whenever sorting numbers.

function customSort(a, b){
     return a - b; 
}
console.log([-11,-2, 0 ,100].sort(customSort));

This customSort() function will sort the array in_place in ascending order.

Roshan Raju
  • 51
  • 1
  • 2
4

Between them, the existing answers tell you everything, but none of them mention both of the problems in your code. Here's the full answer:

The sort isn't doing what you want because the default sort is lexical (i.e. the array elements are converted to strings and compared alphabetically). You can provide your own comparison function to sort():

x.sort(function(a, b) {
    return a - b;
});

Secondly, for...in is actually telling you nothing concrete about whether your array is sorted correctly, because the enumeration of for...in is not defined (even though most but not all browsers do broadly what you'd expect). Use a for loop instead (as indeed you generally should for arrays):

for (var i = 0, len = x.length; i < len; ++i) {
    alert(x[i]);
}
Tim Down
  • 318,141
  • 75
  • 454
  • 536
2

You are not iterating properly. It should be:

for (var i = 0; i < x.length; i++) {
    alert(x[i]);
}

When you use for..in in javascript this will loop through the properties of the object and the order of iteration is undefined. You should be seeing some strange output as well such as all the functions defined in the Array class.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • That part is definitely hinky, and people shouldn't be using `for...in` for arrays for reasons just like this, but the input and output suggests it's not causing the OP's specific issue in his specific browser. The array is actually sorted, just not as expected. – cHao May 23 '11 at 07:26