从这个最初的问题,我将如何在多个字段应用排序?

使用这种稍作调整的结构,我将如何排序城市(上升)和价格(下降)?

var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];

我喜欢的事实是,给出的答案提供了一个一般的方法。在我计划使用这段代码的地方,我将不得不对日期以及其他东西进行排序。“启动”对象的能力似乎很方便,如果不是有点麻烦的话。

我试图把这个答案构建成一个很好的通用示例,但我运气不太好。


当前回答

以下是我的简历,请参考,并举例说明:

function msort(arr, ...compFns) {
  let fn = compFns[0];
  arr = [].concat(arr);
  let arr1 = [];
  while (arr.length > 0) {
    let arr2 = arr.splice(0, 1);
    for (let i = arr.length; i > 0;) {
      if (fn(arr2[0], arr[--i]) === 0) {
        arr2 = arr2.concat(arr.splice(i, 1));
      }
    }
    arr1.push(arr2);
  }

  arr1.sort(function (a, b) {
    return fn(a[0], b[0]);
  });

  compFns = compFns.slice(1);
  let res = [];
  arr1.map(a1 => {
    if (compFns.length > 0) a1 = msort(a1, ...compFns);
    a1.map(a2 => res.push(a2));
  });
  return res;
}

let tstArr = [{ id: 1, sex: 'o' }, { id: 2, sex: 'm' }, { id: 3, sex: 'm' }, { id: 4, sex: 'f' }, { id: 5, sex: 'm' }, { id: 6, sex: 'o' }, { id: 7, sex: 'f' }];

function tstFn1(a, b) {
  if (a.sex > b.sex) return 1;
  else if (a.sex < b.sex) return -1;
  return 0;
}

function tstFn2(a, b) {
  if (a.id > b.id) return -1;
  else if (a.id < b.id) return 1;
  return 0;
}

console.log(JSON.stringify(msort(tstArr, tstFn1, tstFn2)));
//output:
//[{"id":7,"sex":"f"},{"id":4,"sex":"f"},{"id":5,"sex":"m"},{"id":3,"sex":"m"},{"id":2,"sex":"m"},{"id":6,"sex":"o"},{"id":1,"sex":"o"}]

其他回答

这是一个完全的欺骗,但我认为它为这个问题增加了价值,因为它基本上是一个罐装的库函数,你可以开箱即用。

如果你的代码可以访问lodash或者一个与lodash兼容的库,比如下划线,那么你可以使用_。sortBy方法。下面的代码片段直接复制自lodash文档。

示例中的注释结果看起来像是返回数组的数组,但这只是显示了顺序,而不是实际的结果,它是一个对象数组。

var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 36 },
  { 'user': 'fred',   'age': 40 },
  { 'user': 'barney', 'age': 34 }
];

_.sortBy(users, [function(o) { return o.user; }]);
 // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]

_.sortBy(users, ['user', 'age']);
// => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
homes.sort(function(a,b) { return a.city - b.city } );
homes.sort(function(a,b){
    if (a.city==b.city){
        return parseFloat(b.price) - parseFloat(a.price);
    } else {
        return 0;
    }
});

一个动态的方法来做到这与多个键:

从排序的每个col/key中过滤唯一的值 按顺序排列或颠倒 根据indexOf(value)键值为每个对象添加weights width zeropad 使用计算的权重进行排序

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) { 
    sorts.map(sort => {            
        sort.uniques = Array.from(
            new Set(this.map(obj => obj[sort.key]))
        );
        
        sort.uniques = sort.uniques.sort((a, b) => {
            if (typeof a == 'string') {
                return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
            }
            else if (typeof a == 'number') {
                return sort.inverse ? b - a : a - b;
            }
            else if (typeof a == 'boolean') {
                let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                return x;
            }
            return 0;
        });
    });

    const weightOfObject = (obj) => {
        let weight = "";
        sorts.map(sort => {
            let zeropad = `${sort.uniques.length}`.length;
            weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
        });
        //obj.weight = weight; // if you need to see weights
        return weight;
    }

    this.sort((a, b) => {
        return weightOfObject(a).localeCompare( weightOfObject(b) );
    });
    
    return this;
}
});

Use:

// works with string, number and boolean
let sortered = your_array.orderBy([
    {key: "type", inverse: false}, 
    {key: "title", inverse: false},
    {key: "spot", inverse: false},
    {key: "internal", inverse: true}
]);

这里有一个简单的泛型函数方法。使用数组指定排序顺序。前置减号以指定降序。

var homes = [
    {"h_id":"3", "city":"Dallas", "state":"TX","zip":"75201","price":"162500"},
    {"h_id":"4","city":"Bevery Hills", "state":"CA", "zip":"90210", "price":"319250"},
    {"h_id":"6", "city":"Dallas", "state":"TX", "zip":"75000", "price":"556699"},
    {"h_id":"5", "city":"New York", "state":"NY", "zip":"00010", "price":"962500"}
    ];

homes.sort(fieldSorter(['city', '-price']));
// homes.sort(fieldSorter(['zip', '-state', 'price'])); // alternative

function fieldSorter(fields) {
    return function (a, b) {
        return fields
            .map(function (o) {
                var dir = 1;
                if (o[0] === '-') {
                   dir = -1;
                   o=o.substring(1);
                }
                if (a[o] > b[o]) return dir;
                if (a[o] < b[o]) return -(dir);
                return 0;
            })
            .reduce(function firstNonZeroValue (p,n) {
                return p ? p : n;
            }, 0);
    };
}

编辑:在ES6中它甚至更短!

"use strict"; const fieldSorter = (fields) => (a, b) => fields.map(o => { let dir = 1; if (o[0] === '-') { dir = -1; o=o.substring(1); } return a[o] > b[o] ? dir : a[o] < b[o] ? -(dir) : 0; }).reduce((p, n) => p ? p : n, 0); const homes = [{"h_id":"3", "city":"Dallas", "state":"TX","zip":"75201","price":162500}, {"h_id":"4","city":"Bevery Hills", "state":"CA", "zip":"90210", "price":319250},{"h_id":"6", "city":"Dallas", "state":"TX", "zip":"75000", "price":556699},{"h_id":"5", "city":"New York", "state":"NY", "zip":"00010", "price":962500}]; const sortedHomes = homes.sort(fieldSorter(['state', '-price'])); document.write('<pre>' + JSON.stringify(sortedHomes, null, '\t') + '</pre>')

这里' affiliation duedate '和'Title'是列,两者都是升序排序。

array.sort(function(a, b) {

               if (a.AffiliateDueDate > b.AffiliateDueDate ) return 1;
               else if (a.AffiliateDueDate < b.AffiliateDueDate ) return -1;
               else if (a.Title > b.Title ) return 1;
               else if (a.Title < b.Title ) return -1;
               else return 0;
             })