IE8中的Javascript:如何通过字母数字属性对对象数组进行排序

时间:2010-09-28 23:29:31

标签: javascript sorting

我有一个Javascript对象数组,我想通过一个属性进行交叉兼容排序,该属性总是一个正整数,末尾有一个可选的单个字母。我正在寻找一种至少适用于Firefox 3和Internet Explorer 8的解决方案。我最接近这种排序功能的是:

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);
});

如此排序后,打印出arrayOfObjects会给出:

1,foo,big
1010,foo,小
15,foo,小
1A,吧,大
1B,吧,小
1C,吧,小
1D,酒吧,大
1E,酒吧,大
1F,酒吧,大
1G,foo,小
2,foo,小
23,foo,小
23C,foo,小
3,foo,小

但是,我希望arrayOfObjects按以下顺序打印出来:

1,foo,big
1A,吧,大
1B,吧,小
1C,吧,小
1D,酒吧,大
1E,酒吧,大
1F,酒吧,大
1G,foo,小
2,foo,小
3,foo,小
15,foo,小
23,foo,小
23C,foo,小
1010,foo,小

鉴于此,我如何修复上述功能,以便对象按编号排序为主键,字母为辅助键?提前感谢您的帮助。

3 个答案:

答案 0 :(得分: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;
  }
})());

这个想法是将键分成数字和字符串部分。

编辑(oops向后调用“匹配”)

再次编辑 @Ryan Tenney明智地建议匿名外部函数不是必需的:

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;     
});
有点简单。

答案 1 :(得分:0)

您不需要从一串数字中解析整数 -

如果两个数字串匹配,则值无关紧要,您可以查看可能的字母。

如果数字不匹配,则从另一个中减去一个数字会强制数字。

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];
    });

答案 2 :(得分:0)

这是比较函数,带有更详细的代码和有意义的变量名称:

/**
* 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
}