Como classificar uma matriz por uma propriedade de data

698

Digamos que eu tenha uma matriz de alguns objetos:

var array = [{id: 1, date: Mar 12 2012 10:00:00 AM}, {id: 2, date: Mar 8 2012 08:00:00 AM}];

Como posso classificar essa matriz pelo elemento date em ordem a partir da data mais próxima da data e hora atuais? Lembre-se de que a matriz pode ter muitos objetos, mas por uma questão de simplicidade, usei 2.

Eu usaria a função de classificação e um comparador personalizado?

ATUALIZAR:

No meu caso específico, eu queria as datas organizadas da mais recente à mais antiga. Acabei que tive que reverter a lógica da função simples da seguinte maneira:

array.sort(function(a, b) {
    a = new Date(a.dateModified);
    b = new Date(b.dateModified);
    return a>b ? -1 : a<b ? 1 : 0;
});

Isso classifica as datas das mais recentes.

ryandlf
fonte
Se você usar o construtor Date, verifique este primeiro stackoverflow.com/questions/5619202/…
ohkts11 17/17
a maneira mais rápida é usar o módulo de matriz de classificação isomórfica que funciona nativamente no navegador e no nó, suportando qualquer tipo de entrada, campos calculados e ordens de classificação personalizadas.
Lloyd

Respostas:

1403

Resposta mais simples

array.sort(function(a,b){
  // Turn your strings into dates, and then subtract them
  // to get a value that is either negative, positive, or zero.
  return new Date(b.date) - new Date(a.date);
});

Resposta mais genérica

array.sort(function(o1,o2){
  if (sort_o1_before_o2)    return -1;
  else if(sort_o1_after_o2) return  1;
  else                      return  0;
});

Ou mais sucintamente:

array.sort(function(o1,o2){
  return sort_o1_before_o2 ? -1 : sort_o1_after_o2 ? 1 : 0;
});

Resposta poderosa e genérica

Defina uma sortByfunção não enumerável personalizada usando uma transformação Schwartzian em todas as matrizes:

(function(){
  if (typeof Object.defineProperty === 'function'){
    try{Object.defineProperty(Array.prototype,'sortBy',{value:sb}); }catch(e){}
  }
  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;
  }
})();

Use-o assim:

array.sortBy(function(o){ return o.date });

Se a sua data não for diretamente comparável, faça uma data comparável, por exemplo,

array.sortBy(function(o){ return new Date( o.date ) });

Você também pode usar isso para classificar por vários critérios se retornar uma matriz de valores:

// Sort by date, then score (reversed), then name
array.sortBy(function(o){ return [ o.date, -o.score, o.name ] };

Consulte http://phrogz.net/JS/Array.prototype.sortBy.js para obter mais detalhes.

Phrogz
fonte
2
Por que simplesmente não está return b-a;na resposta simples?
Corbacho #
19
Não recomendamos a criação de novos objetos Date dentro do método de classificação. Atingiram problemas de desempenho de produção especificamente por esse motivo. Não aloque memória (e GC) dentro de um método de classificação.
MikeMurko 13/07/19
4
a primeira sintaxe, por exemplo, dá erro no angular7: O lado esquerdo de uma operação aritmética deve ser do tipo 'qualquer', 'número', 'bigint' ou um tipo de enum
SURENDRANATH SONAWANE
1
@MikeMurko, o que você fez para corrigi-lo?
Sireini 23/04
@SURENDRANATHSONAWANE converte Data em carimbo de data / hora do Unix: retorna nova data (b.date) .getTime () - nova data (a.date) .getTime ();
Robert Ostrowicki
147

As respostas do @Phrogz são ótimas, mas aqui está uma resposta ótima e mais concisa:

array.sort(function(a,b){return a.getTime() - b.getTime()});

Usando o modo de seta

array.sort((a,b)=>a.getTime()-b.getTime());

Encontre aqui: Classificar data em Javascript

Garota
fonte
15
Fazer as contas diretamente a - btambém funcionaria. Então, array.sort((a, b) => a - b)(ES6)
yckart
Esta é uma boa solução ao usar o Typecript.
maartenpaauw
72

Depois de corrigir o JSON, isso deve funcionar para você agora:

var array = [{id: 1, date:'Mar 12 2012 10:00:00 AM'}, {id: 2, date:'Mar 8 2012 08:00:00 AM'}];


array.sort(function(a, b) {
    var c = new Date(a.date);
    var d = new Date(b.date);
    return c-d;
});
qw3n
fonte
45

Seus dados precisam de algumas correções:

var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];

Depois de corrigir os dados, você pode usar este pedaço de código:

function sortFunction(a,b){  
    var dateA = new Date(a.date).getTime();
    var dateB = new Date(b.date).getTime();
    return dateA > dateB ? 1 : -1;  
}; 

var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];
array.sort(sortFunction);​
gabitzish
fonte
Para quem usa o Typecript, eu consegui classificar por data usando essa função, enquanto os outros usando a subtração de data falharam.
Danchat 14/01
24

Eu recomendo o GitHub: Array sortBy - uma melhor implementação de sortBymétodo que usa a transformação Schwartziana

Mas, por enquanto, vamos tentar essa abordagem Gist: sortBy-old.js .
Vamos criar um método para classificar matrizes capazes de organizar objetos por alguma propriedade.

Criando a função de classificação

var sortBy = (function () {
  var toString = Object.prototype.toString,
      // default parser function
      parse = function (x) { return x; },
      // gets the item to be sorted
      getItem = function (x) {
        var isObject = x != null && typeof x === "object";
        var isProp = isObject && this.prop in x;
        return this.parser(isProp ? x[this.prop] : x);
      };

  /**
   * Sorts an array of elements.
   *
   * @param {Array} array: the collection to sort
   * @param {Object} cfg: the configuration options
   * @property {String}   cfg.prop: property name (if it is an Array of objects)
   * @property {Boolean}  cfg.desc: determines whether the sort is descending
   * @property {Function} cfg.parser: function to parse the items to expected type
   * @return {Array}
   */
  return function sortby (array, cfg) {
    if (!(array instanceof Array && array.length)) return [];
    if (toString.call(cfg) !== "[object Object]") cfg = {};
    if (typeof cfg.parser !== "function") cfg.parser = parse;
    cfg.desc = !!cfg.desc ? -1 : 1;
    return array.sort(function (a, b) {
      a = getItem.call(cfg, a);
      b = getItem.call(cfg, b);
      return cfg.desc * (a < b ? -1 : +(a > b));
    });
  };

}());

Configurando dados não classificados

var data = [
  {date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: 0,   type: "cash"},
  {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
  {date: "2011-11-14T16:30:43Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T17:22:59Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:53:41Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:48:46Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"},
  {date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-14T16:58:03Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-14T17:07:21Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0,   type: "cash"}
];

Usando isso

Por fim, organizamos a matriz, por "date"propriedade comostring

//sort the object by a property (ascending)
//sorting takes into account uppercase and lowercase
sortBy(data, { prop: "date" });

Se você deseja ignorar letras maiúsculas, defina o "parser"retorno de chamada:

//sort the object by a property (descending)
//sorting ignores uppercase and lowercase
sortBy(data, {
    prop: "date",
    desc: true,
    parser: function (item) {
        //ignore case sensitive
        return item.toUpperCase();
    }
});

Se você deseja tratar o campo "data" como Datetipo:

//sort the object by a property (ascending)
//sorting parses each item to Date type
sortBy(data, {
    prop: "date",
    parser: function (item) {
        return new Date(item);
    }
});

Aqui você pode jogar com o exemplo acima:
jsbin.com/lesebi

jherax
fonte
1
O IE11 teve um problema com a linha: if (toString.call (cfg)! == "[objeto Objeto]") cfg = {}; Se você substituí-lo por if (Object.prototype.toString.call (cfg)! == "[objeto Objeto]") cfg = {}; você também ficará bem com o IE11.
skribbz14
1
Excelente solução
Moses Machua
14

Isso deve ocorrer quando a data estiver neste formato (dd / mm / aaaa).

  sortByDate(arr) {
    arr.sort(function(a,b){
      return Number(new Date(a.readableDate)) - Number(new Date(b.readableDate));
    });

    return arr;
  }

Então ligue sortByDate(myArr);

Edison D'souza
fonte
12

Você pode usar sortBy no sublinhado js.

http://underscorejs.org/#sortBy

Amostra:

var log = [{date: '2016-01-16T05:23:38+00:00', other: 'sample'}, 
           {date: '2016-01-13T05:23:38+00:00',other: 'sample'}, 
           {date: '2016-01-15T11:23:38+00:00', other: 'sample'}];

console.log(_.sortBy(log, 'date'));
Robert
fonte
Maneira perfeita e mais curta de fazê-lo!
Bhavik Kalariya
8

Vou adicionar isso aqui, pois alguns usos podem não ser capazes de descobrir como inverter esse método de classificação.

Para classificar por 'chegando', podemos simplesmente trocar a & b, assim:

your_array.sort ( (a, b) => {
      return new Date(a.DateTime) - new Date(b.DateTime);
});

Observe que aagora está no lado esquerdo e bno lado direito: D!

James111
fonte
7

Eu pessoalmente uso a seguinte abordagem para classificar datas.

let array = ["July 11, 1960", "February 1, 1974", "July 11, 1615", "October 18, 1851", "November 12, 1995"];

array.sort(function(date1, date2) {
   date1 = new Date(date1);
   date2 = new Date(date2);
   if (date1 > date2) return 1;
   if (date1 < date2) return -1;
})
Aravinda Meewalaarachchi
fonte
6

Consegui realizar a classificação usando as linhas abaixo:

array.sort(function(a, b)
{
   if (a.DueDate > b.DueDate) return 1;
   if (a.DueDate < b.DueDate) return -1;
})
Amay Kulkarni
fonte
5
Adding absolute will give better results

var datesArray =[
      {"some":"data1","date": "2018-06-30T13:40:31.493Z"},
      {"some":"data2","date": "2018-07-04T13:40:31.493Z"},
      {"some":"data3","date": "2018-06-27T13:40:54.394Z"}
   ]

var sortedJsObjects = datesArray.sort(function(a,b){ 
    return Math.abs(new Date(a.date) - new Date(b.date)) 
});
Rajiv Shrivastava
fonte
2

Para quem deseja classificar por data (formato do Reino Unido), usei o seguinte:

//Sort by day, then month, then year
for(i=0;i<=2; i++){
    dataCourses.sort(function(a, b){

        a = a.lastAccessed.split("/");
        b = b.lastAccessed.split("/");

        return a[i]>b[i] ? -1 : a[i]<b[i] ? 1 : 0;
    }); 
}
E eu
fonte
2

Acabei de pegar a transformação schwartziana descrita acima e a fiz como função. É preciso um array, a classificação functione um booleano como entrada:

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

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

arr = []
arr.push({
  date: new Date(1494434112806)
})
arr.push({
  date: new Date(1494434118181)
})
arr.push({
  date: new Date(1494434127341)
})

console.log(JSON.stringify(arr));

arr = schwartzianSort(arr, function(o) {
  return o.date
}, false)
console.log("DESC", JSON.stringify(arr));

arr = schwartzianSort(arr, function(o) {
  return o.date
}, true)
console.log("ASC", JSON.stringify(arr));

Loretoparisi
fonte
2

Obrigado Ganesh Sanap. classificando itens por campo de data do antigo para o novo. Use-o

 myArray = [{transport: "Air",
             load: "Vatican Vaticano",
             created: "01/31/2020"},
            {transport: "Air",
             load: "Paris",
             created: "01/30/2020"}] 

        myAarray.sort(function(a, b) {
            var c = new Date(a.created);
            var d = new Date(b.created);
            return c-d;
        });
Янов Алексей
fonte
1
Qual é o motivo menos?
Янов Алексей 31/01
2

Se, como eu, você tem uma matriz com datas formatadas como YYYY[-MM[-DD]]onde você gostaria de solicitar datas mais específicas antes de datas menos específicas, criei esta útil função:

function sortByDateSpecificity(a, b) {
  const aLength = a.date.length
  const bLength = b.date.length
  const aDate = a.date + (aLength < 10 ? '-12-31'.slice(-10 + aLength) : '')
  const bDate = b.date + (bLength < 10 ? '-12-31'.slice(-10 + bLength) : '')
  return new Date(aDate) - new Date(bDate)
}
daviestar
fonte
0
["12 Jan 2018" , "1 Dec 2018", "04 May 2018"].sort(function(a,b) {
    return new Date(a).getTime() - new Date(b).getTime()
})
Shravan Shetty
fonte
Explique brevemente sua resposta e verifique a formatação do seu código.
dthulke
Falhará em datas antigas.
Oliver Dixon