JavaScript按Chrome中的多个字段排序对象数组

时间:2014-07-29 14:14:53

标签: javascript google-chrome sorting

从它的内容来看,这听起来很简单,但我还没有成功地在Chrome中取得完美的成绩(我在IE中做到了)

所以我有一个对象:

var objs=[
{ name: "water", type: "cold" },
{ name: "tea", type: "hot" },
{ name: "coffee", type: "hot" },
{ name: "choco", type: "cold" }
];

我按名称排序,升序,我得到了预期的结果:

  1. 巧克力,冷
  2. 咖啡,热
  3. 茶,热
  4. 水,冷
  5. 我在IE和Chrome中都得到了相同的结果,

    然后,我按类型,升序和期望再次对其进行排序:

    1. choco,cold
    2. 水,冷
    3. 咖啡,热
    4. 茶,热
    5. 但是我只在IE中获得了预期的结果,而在Chrome中,结果几乎相同,除了" water"来到顶部(它破坏了第一次排序)

      任何一般方法的想法? (我需要为每个字段保留一个函数调用,而不是同时在一个函数中按多个字段排序)

      我的排序方法是这样的:

      function SortBy(key,Asc,method){
        var GetKey=function(x) {return method ? method(x[key]) : x[key] };
        return function(a,b){
          var A=GetKey(a), B=GetKey(b);
          return ((A<B) ? -1 : ((A>B) ? 1 : 0)) * [-1,1][+!!Asc];
        }
      }
      
      var sortedObjects=Clone(objs); //clone the current objs
      
      sortedObjects.sort(SortBy("name" , true, function(x){
        if (typeof(x)=="string") return x.toLowerCase(); else return x;
      }));
      
      objs=sortedObjects; //got the first result
      
      sortedObjects.sort(SortBy("type",true,function(x){
        if (typeof(x)=="string") return x.toLowerCase(); else return x;
      }));
      
      objs=sortedObjects;
      

      已编辑这里是小提琴(问题是&#34; Water&#34;):DEMO

2 个答案:

答案 0 :(得分:1)

如果我们阅读 ES5规范 §15.4.4.11 Array.prototype.sort,则第二句话说明

  

排序不一定稳定(也就是说,比较相等的元素不一定保持原始顺序)

也就是说,在 JavaScript 中,如果比较器说两件事情是相等的(通过给出0),那么它们是否被交换并不重要。因此,在某些环境中,由于某些其他原因(例如哈希或仅实施),它们可能会交换。

即。您遇到的结果是由规范定义的sort的有效结果,并且重复相同的sort甚至可能每次都会给出不同的结果


希望我不会为此付出过多的代价,但如果你把它作为一个功能那么做,那么你就不需要多次遍历数组而你将避免意外结果

/*  list = multiSort(list [, obj, ...])
 *  where e.g. obj = {
 *      key: "keyToLookAt",
 *      optional comparator: function (a, b) {return a<b || ((a===b)-1);},
 *      optional ascending: default true
 *  }
*/

var multiSort = (function () {
    function generateSorter(key, comparator, ascending) {
        ascending = 2 * !!ascending - 1;
        if (comparator) {
            return function sorter(a, b) {
                return ascending * comparator(a[key], b[key]);
            };
        }
        return function sorter(a, b) {
            a = a[key];
            b = b[key];
            return ascending * (a < b ? -1 : a > b ? 1 : 0);
        };
    }
    function sortManager(sorters) {
        return function (a, b) {
            var ret, i = 0;
            for (; i < sorters.length; ++i) {
                ret = sorters[i](a, b);
                if (ret !== 0) return ret;
            }
            return 0;
        };
    }
    function multiSort(list) {
        var i = 1, sorters = [];
        for (; i < arguments.length; ++i) {
            sorters.push(generateSorter(
                arguments[i].key,
                arguments[i].comparator,
                'ascending' in arguments[i] ? arguments[i].ascending : 1
            ));
        }
        list.sort(sortManager(sorters));
        return list;
    }
    return multiSort;
}());

然后在使用它时,最严格的&#34;排序规则首先

multiSort(
    [
        { name: "water", type: "cold" },
        { name: "tea", type: "hot" },
        { name: "coffee", type: "hot" },
        { name: "choco", type: "cold" }
    ],
    {key: 'type'},
    {key: 'name'}
);
/*
[
    { "name": "choco" , "type": "cold" },
    { "name": "water" , "type": "cold" },
    { "name": "coffee", "type": "hot" },
    { "name": "tea"   , "type": "hot" }
]
*/

答案 1 :(得分:0)

我创建了一个CodePen来测试并正常工作...... 我用更易读的代码写了相同的想法

function SortBy(key, isAsc, fn){
     fn = fn || function (x){ return x; };

    return function(objA, objB){
       var a = fn(objA[key]);
       var b = fn(objB[key]);

       var isGreater = isAsc ? 1 : -1;
       var isLesser = -isGreater;
       var isSame = 0;

       if( a > b ) return isGreater;
       if( a == b ) return isSame;
       if( a < b ) return isLesser;
       return -1; //to down the undefined

     }  

}

http://codepen.io/anon/pen/sGgDq使用大量数据进行了编辑和测试

p.s。:我使用了codepen,因为jsfiddle在我的工作中没有打开