I am having trouble sorting an array that includes undefined elements (a sparse array) in IE7. This works great in Safari and Firefox of course, and I haven't tried other versions of IE, but here is a simple example.

<html>
<head>
<script type="text/javascript">
function runscript() {
    var myArray = [{id: 2},
                        undefined,
                        {id: 0},
                        {id: 1},
                        {id: 3},
                        {id: 4},
                        {id: 5}];
    myArray.sort(function compare(a, b) { return a.id - b.id; });
    var output = '';
    for (loop in myArray) {
        output += myArray[loop].id + ' ';
    }
    alert(output);
}
</script>
</head>
<body onLoad="runscript();">
</body>

The alert() at the end inexplicably shows 0 2 3 4 5 1. Removing the undefined element from the array correctly sorts it and the alert shows 0 1 2 3 4 5.

Is there a way to work around this in IE7 so that I can reliably sort arrays that include undefined elements? I don't care where the undefined elements end up as long as the defined elements are sorted correctly.

share|improve this question
feedback

3 Answers

up vote 1 down vote accepted

Try changing for (loop in myArray) to for (var loop=0; loop<myArray.length; loop++):

function runscript() {
    var myArray = [{id: 2},
                        undefined,
                        {id: 0},
                        {id: 1},
                        {id: 3},
                        {id: 4},
                        {id: 5}];
    myArray.sort(function compare(a, b) { return a.id - b.id; });
    var output = '';
    for (var loop=0; loop<myArray.length; loop++) {
        output += (myArray[loop]||{id: 'undefined'}).id + ' ';
    }
    alert(output);
}
runscript()

when using the for (x in object) the items aren't guaranteed to be in in order. See also http://stackoverflow.com/questions/500504/javascript-for-in-with-arrays

(The above alerts 0 1 2 3 4 5 undefined)

EDIT: Undeleted - I've tested the above and it works :-P

share|improve this answer
I was assuming that for (loop in myArray) would respect the natural array ordering after a sort, and in fact it seems to in Safari, Firefox and even IE7 (but only when there are no undefined values in the array). If I do an indexed loop as David suggests, it works across all browsers. Too bad, I was just starting to get used to the more compact loop syntax. Thanks for your help. – Gene Goykhman May 21 '10 at 20:15
feedback

First of all, your sort function is wrong as it is expected to return -1, 0 or +1, not a boolean value.
Use this instead

var arr = [.....]
arr.sort((function(a, b){
    if (!a || !b) {
        // Here you choose how to treat undefined/null elements
        return 0;
    }  
    return (a[index].id === b[index].id ? 0 : (a[index].id < b[index].id ? -1 : 1));
})

But just so that you know, that loop of yours is going to throw an error when trying to return the id property from the undefined element. Also, you should never use a for..in loop to iterate over an array, use either a loop with incrementing index or a reverse while like this

var l = arr.length; 
while (l--) {
    ..
}
share|improve this answer
feedback

Maybe you can modify your comparator

myArray.sort(function compare(a, b) { return a.id || 0 - b.id || 0; });
share|improve this answer
Hi Kunal, this seems to work but I have no idea why. Can you explain the comparator function a little bit? – Gene Goykhman May 21 '10 at 7:41
Yes. Custom comparator for sort is suppose to return integer value ( +ve, -ve or 0 only ). In the above scenario, when the value (a.id) is undefined, the sort function return NaN which is incorrect. – Kunal May 21 '10 at 8:06
+1 - I find it surprising that this function works at all, after all undefined.id raises an exception (undefined.id' is null or not an object in IE). Maybe array sorting functions have a special case to return undefined if properties are accessed in undefined types? – cryo May 21 '10 at 8:18
@David, It will throw exception if you try to compare the value like if( a.id == 10 ) { // do something. } – Kunal May 21 '10 at 8:59
Are you sure this function works as expected? In my copy of IE8 it alerts 0 1 2 4 3 5. Besides, the function should be return (a.id || 0) - (b.id || 0); because of the operator precedence in JavaScript. When I alert each value in the array, it doesn't popup with any undefined values - it looks like sorting functions only work on strings, numbers and objects like hash tables and arrays (and IE sorts the rest internally to the end of the array.) My answer of for (var i in myArray) replaced with for (var i=0; i<myArray.length; i++) alerts the correct answer, so I'll undelete it :-P – cryo May 21 '10 at 10:01
feedback

Your Answer

 
or
required, but never shown
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.