Подтвердить что ты не робот

Сортировка массива объектов двумя свойствами

У меня есть массив объектов, которые я хочу сортировать по двум свойствам:

  • RemindingTimestamp
  • ModificationTimestamp

Порядок сортировки: desc

Сортировка этого объекта с помощью одного свойства не является проблемой, но в этом случае я понятия не имею, как заставить его работать.

4b9b3361

Ответ 1

Предполагая, что сами метки времени выглядят нормально (например, ISO8601 и тот же часовой пояс), попробуйте:

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

Изменить - ответ на комментарии

Понижающий сортировка достигается путем изменения порядка вычитания или умножения результата на -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

Преобразование объекта даты в дату может быть расширено для обработки часового пояса, если это необходимо (только для строк, совместимых только с ISO8601, те, которые используют аббревиатуры часового пояса вместо фактического смещения, ненадежны).

Ответ 2

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

Ресурсы

Ответ 3

Пользовательские компараторы принимают форму:

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

Для нисходящей сортировки замените < и > (или свопинг 1 и -1).

В то время как вы можете сделать свой собственный собственный компаратор каждый раз, когда вам это нужно, я создал метод, разработанный явно для легкой сортировки по нескольким критериям, используя Schwartzian (в некоторых случаях это может быть быстрее, но больше голода): http://phrogz.net/js/Array.prototype.sortBy.js

Короче:

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

reverse существует, так как вы упомянули, что хотите сортировку по убыванию. Если оба RemindingTimestamp и ModificationTimestamp являются числами, вы также можете:

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

Вот код, который добавляет sortBy в массивы:

(function(){
  // Extend Arrays in a safe, non-enumerable way
  if (typeof Object.defineProperty === 'function'){
    // Guard against IE8 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;
  }
})();

Вот еще несколько примеров из документов:

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"]

Обратите внимание, что в последнем примере (typeof this) бывает не таким, как (typeof o); см. этот пост для более подробной информации.

Ответ 4

Предполагая, что оба свойства находятся в одном и том же сортируемом формате, здесь другой способ глубокой сортировки в 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);

Надеюсь, это поможет кому-то.

Ответ 5

Другой способ

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