【问题标题】:Javascript in IE8: how to sort array of objects by alphanumeric propertyIE8 中的 Javascript:如何按字母数字属性对对象数组进行排序
【发布时间】:2014-09-24 18:22:02
【问题描述】:

我有一个 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,富,大
1010,富,小
15、富、小
1A,吧台,大
1B,酒吧,小
1C,酒吧,小
一维,酒吧,大
1E,酒吧,大
1F,酒吧,大
1G,富,小
2、富、小
23、富、小
23C, foo, 小
3、foo、小

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

1,富,大
1A,吧台,大
1B,酒吧,小
1C,酒吧,小
一维,酒吧,大
1E,酒吧,大
1F,酒吧,大
1G,富,小
2、富、小
3、富、小
15、富、小
23、富、小
23C, foo, 小
1010, foo, 小

鉴于此,我怎样才能修复上述功能,以便对象按数字作为主键和字母作为辅助键排序?提前感谢您的帮助。

【问题讨论】:

    标签: javascript sorting


    【解决方案1】:
    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;
      }
    })());
    

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

    编辑(哎呀,“匹配”调用向后)

    再次编辑 @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;     
    });
    

    简单一点。

    【讨论】:

    • 正则表达式文字不会为每次迭代增加任何成本。您最好摆脱外部自执行函数并在内部函数中声明拆分器。
    • 除此之外,很好的答案。它比我准备提供的答案要简洁得多:)
    • 我有一个关于重复正则表达式的事情 - 它不是为了性能,而是为了维护。也许一百次尝试我会在第一时间得到一个正则表达式,所以我想尽量减少重复它的次数。当然,我可以在函数体中将其输入为var;我并没有想太多。
    • 我认为您可以将第一个返回更改为 return a[2] &lt; b[2] ? -1 : 1; 并且仍然可以正常排序。
    • @Daniel 很好,这可能会使排序不稳定 - “稳定”排序是将已经有序的元素(由于键相等)以相同的顺序保留,而“不稳定”排序可以置换这些。我不确定这是不是真的,但我总是明确地检查键是否相等,以便稳定的排序可以真正保持稳定。
    【解决方案2】:

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

    如果两个数字串匹配,数值无所谓,你看一个可能的字母。

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

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

    【讨论】:

      【解决方案3】:

      这里是比较函数,代码更冗长,变量名更有意义:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-25
        • 1970-01-01
        • 2020-08-24
        • 1970-01-01
        • 1970-01-01
        • 2011-09-06
        相关资源
        最近更新 更多