javascript 按两个属性对对象数组进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10153846/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 08:51:26  来源:igfitidea点击:

Sorting an Array of Objects by two Properties

javascriptsorting

提问by Sven Kannenberg

I've got an Array of Objects I want to sort by two Properties:

我有一个对象数组,我想按两个属性排序:

  1. RemindingTimestamp
  2. ModificationTimestamp
  1. 提醒时间戳
  2. 修改时间戳

Sorting order: desc

排序顺序:desc

Sorting this Object by one Property isn't the problem, but in this case I've no idea how to get it work.

按一个属性对这个对象进行排序不是问题,但在这种情况下,我不知道如何让它工作。

回答by RobG

Presuming the timestamps themselves sort ok (e.g. ISO8601 and same time zone), try:

假设时间戳本身排序正常(例如 ISO8601 和相同时区),请尝试:

myArray.sort(function(a,b) {
  var x = a.RemindingTimestamp - b.RemindingTimestamp;
  return x == 0? a.ModificationTimestamp - b.ModificationTimestamp : x;
}

Edit - response to comments

编辑 - 回复评论

A descending sort is achieved by changing the order of subtraction, or multiplying the result by -1. Dates that don't sort because they don't subtract (e.g. 2012-04-12) can be handled by conversion to dates first, e.g.

降序排序是通过改变减法顺序或将结果乘以 -1 来实现的。由于不减去(例如 2012-04-12)而不排序的日期可以通过首先转换为日期来处理,例如

// Convert ISO8601 date string to date object
// Assuming date is ISO8601 long format, ignores timezone
function toDate(s) {
  var bits = s.split(/[-T :]/);
  var d = new Date(bits[0], bits[1]-1, bits[2]);
  d.setHours(bits[3], bits[4], parseFloat(bits[5])); 
  return d;
}

// Source data, should end up sorted per n
var myArray = [ 
  {RemindingTimestamp: '2012-04-15T23:15:12Z', 
   ModificationTimestamp: '2012-04-15T23:15:12Z', n: 4},
  {RemindingTimestamp: '2012-04-12T23:15:12Z', 
   ModificationTimestamp: '2012-04-12T23:15:12Z', n: 1},
  {RemindingTimestamp: '2012-04-12T23:15:12Z', 
   ModificationTimestamp: '2012-04-13T23:15:12Z', n: 2},
  {RemindingTimestamp: '2012-04-12T23:15:12Z', 
   ModificationTimestamp: '2012-04-13T23:15:14Z', n: 3}
];

// Sort it
myArray.sort(function(a,b) {
  var x = toDate(a.RemindingTimestamp) - toDate(b.RemindingTimestamp);
  return x? x : toDate(a.ModificationTimestamp) - toDate(b.ModificationTimestamp);
});

// Just to show the result
function sa(o) {
  var result = [], t;
  for (var i=0; i<o.length; i++) {
    t = o[i]; 
      result.push(t.n);
  }
  alert(result);
}

sa(myArray); // 1,2,3,4

The conversion of date string to date object can be extended to handle time zone if required (for ISO8601 compliant strings only, those that use time zone abbreviations instead of the actual offset are unreliable).

如果需要,可以扩展日期字符串到日期对象的转换以处理时区(仅对于符合 ISO8601 的字符串,使用时区缩写而不是实际偏移量的字符串是不可靠的)。

回答by Zeta

function compareObject(obj1, obj2){
    if(obj1.RemindingTimestamp > obj2.RemindingTimestamp)
        return - 1;
    if(obj2.RemindingTimestamp > obj1.RemindingTimestamp)
        return 1;

    // obj1.RemindingTimestamp == obj2.RemindingTimestamp

    if(obj1.ModificationTimestamp > obj2.ModificationTimestamp)
        return -1;
    if(obj2.ModificationTimestamp > obj1.ModificationTimestamp)
        return 1;

    return 0;
}

myObjects.sort(compareObject);

JSFiddle Demo

JSFiddle 演示

Resources:

资源:

回答by Phrogz

Custom comparators take the form:

自定义比较器采用以下形式:

myArray.sort(function(a,b){
  var m1=a1.RemindingTimestamp,
      m2=a2.RemindingTimestamp,
      n1=a1.ModificationTimestamp,
      n2=a2.ModificationTimestamp;
  return m1<m2 ? -1 : m1>m2 ? 1 :
         n1<n2 ? -1 : n1>n2 ? 1 : 0;
});

For descending sort, swap the <and >(or swap 1and -1).

对于降序排序,交换<>(或交换1-1)。

While you can make your own custom comparator each time you need this, I have created a method designed explicitly for easily sorting by multiple criteria, using a Schwartzian transform(which may be faster but more memory hungry in some circumstances): http://phrogz.net/js/Array.prototype.sortBy.js

虽然您可以在每次需要时制作自己的自定义比较器,但我创建了一个明确设计的方法,用于按多个标准轻松排序,使用Schwartzian 变换(可能更快但在某些情况下更需要内存):http:// phrogz.net/js/Array.prototype.sortBy.js

In short:

简而言之:

myArray.sortBy(function(obj){
  return [obj.RemindingTimestamp, obj.ModificationTimestamp];
}).reverse();

The reverseis there since you mentioned that you wanted a descending sort. If both RemindingTimestampand ModificationTimestampare numbers, you could alternatively do:

reverse是有,因为你提到你想要一个降序排序。如果RemindingTimestampModificationTimestamp都是数字,您也可以这样做:

myArray.sortBy(function(obj){
  return [-obj.RemindingTimestamp, -obj.ModificationTimestamp];
});

Here is the code that adds sortByto arrays:

这是添加sortBy到数组的代码:

(function(){
  // Extend Arrays in a safe, non-enumerable way
  if (typeof Object.defineProperty === 'function'){
    // Guard against IE8's broken defineProperty
    try{Object.defineProperty(Array.prototype,'sortBy',{value:sb}); }catch(e){}
  }
  // Fall back to an enumerable implementation
  if (!Array.prototype.sortBy) Array.prototype.sortBy = sb;

  function sb(f){
    for (var i=this.length;i;){
      var o = this[--i];
      this[i] = [].concat(f.call(o,o,i),o);
    }
    this.sort(function(a,b){
      for (var i=0,len=a.length;i<len;++i){
        if (a[i]!=b[i]) return a[i]<b[i]?-1:1;
      }
      return 0;
    });
    for (var i=this.length;i;){
      this[--i]=this[i][this[i].length-1];
    }
    return this;
  }
})();

Here are some more examples from the docs:

以下是文档中的更多示例:

var a=[ {c:"GK",age:37}, {c:"ZK",age:13}, {c:"TK",age:14}, {c:"AK",age:13} ];

a.sortBy( function(){ return this.age } );                                  
  --> [ {c:"ZK",age:13}, {c:"AK",age:13}, {c:"TK",age:14}, {c:"GK",age:37} ]

a.sortBy( function(){ return [this.age,this.c] } );                         
  --> [ {c:"AK",age:13}, {c:"ZK",age:13}, {c:"TK",age:14}, {c:"GK",age:37} ]

a.sortBy( function(){ return -this.age } );                                 
  --> [ {c:"GK",age:37}, {c:"TK",age:14}, {c:"ZK",age:13}, {c:"AK",age:13} ]


var n=[ 1, 99, 15, "2", "100", 3, 34, "foo", "bar" ];

n.sort();
  --> [ 1, "100", 15, "2", 3, 34, 99, "bar", "foo" ]

n.sortBy( function(){ return this*1 } );
  --> [ "foo", "bar", 1, "2", 3, 15, 34, 99, "100" ]

n.sortBy( function(o){ return [typeof o,this] } );
  --> [1, 3, 15, 34, 99, "100", "2", "bar", "foo"]

n.sortBy(function(o){ return [typeof o, typeof o=="string" ? o.length : o] })
  --> [1, 3, 15, 34, 99, "2", "100", "bar", "foo"]

Note in the last example that (typeof this)happens not to be the same as (typeof o); see this postfor more details.

请注意,在最后一个示例中,(typeof this)它与 (typeof o); 不同。有关更多详细信息,请参阅此帖子

回答by gkri

Assuming that both properties are in the same sortable format, here's another way of deep sorting in ES6:

假设两个属性都采用相同的可排序格式,这里是另一种深度排序方式ES6

const comparingFunction = (a, b) => {
  if (a.property1 < b.property1) {
    return -1;
  }
  if (a.property1 > b.property1) {
    return 1;
  }

  if (a.property1 == b.property1) {
    if (a.property2 < b.property2) {
      return -1;
    }
    if (a.property2 > b.property2) {
      return 1;
    }
    return 0;
  }
};

myArrayOfObjects.sort(comparingFunction);

Hope it helps somebody.

希望它可以帮助某人。

回答by Mihai

Another way

另一种方式

function sortBy(ar) {
  return ar.sort((a, b) => a.RemindingTimestamp  === b.RemindingTimestamp  ?
      a.ModificationTimestamp.toString().localeCompare(b.ModificationTimestamp) :
      a.RemindingTimestamp.toString().localeCompare(b.RemindingTimestamp));
}