开发者

Javascript in IE8: how to sort array of objects by alphanumeric property

I've got an array of Javascript objects that I'd like to cross-compatibly sort by a property that is always a positive integer with an optional single letter at the end. I'm looking for a solution that works in at least Firefox 3 and Internet Explorer 8. The closest I've come to such a sort function is the following:

var arrayOfObjects = [{id: '1A', name: 'bar', size: 'big'}, {id: '1C', name: 'bar', size: 'small'}, {id: '1', name: 'foo', size: 'big'}, {id: '1F', name: 'bar', size: 'big'}, {id: '1E', name: 'bar', size: 'big'}, {id: '1B', name: 'bar', s开发者_如何学Cize: 'small'}, {id: '1D', name: 'bar', size: 'big'}, {id: '1G', name: 'foo', size: 'small'},  {id: '3', name: 'foo', size: 'small'}, {id: '23', name: 'foo', size: 'small'}, {id: '2', name: 'foo', size: 'small'}, {id: '1010', name: 'foo', size: 'small'}, {id: '23C', name: 'foo', size: 'small'}, {id: '15', name: 'foo', size: 'small'}]

arrayOfObjects.sort(function(a, b){
    return (a.id < b.id ? -1 : a.id == b.id ? 0 : 1);
});

After being so sorted, printing out arrayOfObjects gives:

1, foo, big

1010, foo, small

15, foo, small

1A, bar, big

1B, bar, small

1C, bar, small

1D, bar, big

1E, bar, big

1F, bar, big

1G, foo, small

2, foo, small

23, foo, small

23C, foo, small

3, foo, small

However, I would like arrayOfObjects to print out in the order below:

1, foo, big

1A, bar, big

1B, bar, small

1C, bar, small

1D, bar, big

1E, bar, big

1F, bar, big

1G, foo, small

2, foo, small

3, foo, small

15, foo, small

23, foo, small

23C, foo, small

1010, foo, small

Given that, how could I fix the above function so that the objects sort by number as primary key and letter as secondary key? Thanks in advance for any help.


arrayOfObjects.sort((function() {
  var splitter = /^(\d+)([A-Z]*)/;
  return function(a, b) {
    a = a.id.match(splitter); b = b.id.match(splitter);
    var anum = parseInt(a[1], 10), bnum = parseInt(b[1], 10);
    if (anum === bnum)
      return a[2] < b[2] ? -1 : a[2] > b[2] ? 1 : 0;
    return anum - bnum;
  }
})());

the idea is to split the keys into the numeric and string parts.

edit (oops got the "match" call backwards)

edit again @Ryan Tenney wisely suggests that the anonymous outer function isn't really necessary:

arrayOfObjects.sort(function(a, b) {
  var splitter = /^(\d+)([A-Z]*)/;
  a = a.id.match(splitter); b = b.id.match(splitter);
  var anum = parseInt(a[1], 10), bnum = parseInt(b[1], 10);
  if (anum === bnum)
    return a[2] < b[2] ? -1 : a[2] > b[2] ? 1 : 0;
  return anum - bnum;     
});

a little simpler.


You don't need to parse the integer out of a string of digits-

If the two strings of digits match, the value doesn't matter, you look at a possible letter.

If the digits don't match, subtracting one from the other coerces the numbers.

var rx=/^(\d+)(\D?)$/;

    arrayOfObjects.sort(function(a, b){ 
        var id_a= a.id.match(rx), id_b= b.id.match(rx);
        if(id_a[1]== id_b[1]){
            if(id_a[2]=== id_b[2]) return 0;
            else{
                if(!id_a[2]) return -1;
                if(!id_b[2]) return 1;
                return id_a[2]> id_b[2]? 1: -1;
            }
        }
        return id_a[1]-id_b[1];
    });


Here is compare function, with a little more verbose code and meaningful variable names:

/**
* Sort array ba numerical & alphabetical order ["1a", "2z", "2a", 99, 100]
*/
function compare(a, b) { 

    var re = /(\d+)([^ ]?)/, numA, numB, charA, charB,
        aMatches = re.exec(a),
        bMatches = re.exec(b) ;

    numA = aMatches[1] ? aMatches[1] : ''; //get the number part
    charA = aMatches[2] ? aMatches[2] : ''; //get the char part

    numB = bMatches[1] ? bMatches[1] : '';
    charB = bMatches[2] ? bMatches[2] : '';

    if (charA || charB){ //if one or both of the compare candidates have letter
        if (numA==numB){ //only if number parts are equal
            return charA.localeCompare(charB); // we compare letters 
        }
    }

    return numA - numB; // otherwise just compare numbers
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜