最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

sorting - Javascript in IE8: how to sort array of objects by alphanumeric property - Stack Overflow

programmeradmin0浏览0评论

I've got an array of Javascript objects that I'd like to cross-patibly 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 e 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', size: '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.

I've got an array of Javascript objects that I'd like to cross-patibly 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 e 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', size: '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.

Share Improve this question asked Sep 28, 2010 at 23:29 jqpjqp 6671 gold badge8 silver badges18 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3
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 pare function, with a little more verbose code and meaningful variable names:

/**
* Sort array ba numerical & alphabetical order ["1a", "2z", "2a", 99, 100]
*/
function pare(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 pare candidates have letter
        if (numA==numB){ //only if number parts are equal
            return charA.localeCompare(charB); // we pare letters 
        }
    }

    return numA - numB; // otherwise just pare numbers
}
发布评论

评论列表(0)

  1. 暂无评论