简体   繁体   English

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

[英]Sorting an Array of Objects by two Properties

I've got an Array of Objects I want to sort by two Properties: 我有一个我想要按两个属性排序的对象数组:

  1. RemindingTimestamp RemindingTimestamp
  2. ModificationTimestamp ModificationTimestamp

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. 通过一个属性对此对象进行排序不是问题,但在这种情况下,我不知道如何使其工作。

Presuming the timestamps themselves sort ok (eg 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. 通过改变减法的顺序或将结果乘以-1来实现降序排序。 Dates that don't sort because they don't subtract (eg 2012-04-12) can be handled by conversion to dates first, eg 由于没有减去而没有排序的日期(例如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兼容字符串,使用时区缩写而不是实际偏移的字符串是不可靠的)。

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: 资源:

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 1 and -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 reverse is there since you mentioned that you wanted a descending sort. reverse ,因为你提到你想要降序排序。 If both RemindingTimestamp and ModificationTimestamp are numbers, you could alternatively do: 如果RemindingTimestampModificationTimestamp都是数字,您可以选择:

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

Here is the code that adds sortBy to 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) ; 在最后一个例子中注意(typeof this)恰好与(typeof o) ; see this post for more details. 有关更多详细信息,请参阅此帖

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. 希望它对某人有帮助。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM