6

I have searched for this question and no existing answer seems to apply. Consider the following:

[
  { 'August 17th 2016': [75] }, // 75 is the length of the array which contains up to 75 objects ... 
  { 'August 1st 2016': [5] },
  { 'August 28th 2016': [5] },
  ...
]

What is the best way to sort the objects in this array by their date and still keep the "english" representation of their key?

Note: The key is used as a chart label.

Everywhere I look array.sort is used, but that's on the object's key of say created_at.

The result should be:

[
  { 'August 1st 2016': [5] },
  { 'August 17th 2016': [75] }
  { 'August 28th 2016': [5] },
  ...
]

I am not sure how to proceed so I don't have anything to show.

Tomas Langkaas
  • 4,551
  • 2
  • 19
  • 34
TheWebs
  • 12,470
  • 30
  • 107
  • 211
  • Maybe a duplicate? http://stackoverflow.com/questions/979256/sorting-an-array-of-javascript-objects – tbg Dec 11 '16 at 19:19
  • Possible duplicate of [Sorting nested arrays of objects by date](http://stackoverflow.com/questions/9293290/sorting-nested-arrays-of-objects-by-date) – stefanhorne Dec 11 '16 at 19:21
  • 2
    Neither of those are proper duplicates given that he wants to sort by key. – Madara's Ghost Dec 11 '16 at 19:27

2 Answers2

6

This can be accomplished by using date.parse on the object key. I took the first object key as it appears there is only 1 in each entry of the array. The tricky part is that date.parse does not work on "12th" or "1st", so, we have to temporarily replace the "th", or "st" with a ,. This way, date.parse works on the string.

var dates = [{
  'August 17th 2016': [75]
}, {
  'August 1st 2016': [5]
}, {
  'August 28th 2016': [5]
}]

const replaceOrdinals = o => {
  return Object.keys(o)[0].replace(/\w{2}( \d+$)/, ',$1');
}

dates = dates.sort((a, b) => {
  return Date.parse(replaceOrdinals(a)) - Date.parse(replaceOrdinals(b))
});

console.log(dates);

Keep in mind:

From @adeneo in the comments: Date.parse is implentation dependant. You will probably want to read through it's documentation to determine if things like time zones will mess things up. As a more sure method, you can use something like moment.js for date parsing.

KevBot
  • 17,900
  • 5
  • 50
  • 68
  • 1
    Should be noted that `Date.parse` is implementation dependant, and won't neccessarely work on those date strings at all in some implementation. – adeneo Dec 11 '16 at 19:36
  • Can you explain this: `replaceOrdinals = o => ` What are we doing here ? @KevBot – TheWebs Dec 11 '16 at 19:47
  • @TheWebs, it is an [`arrow function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). The ES5 version would be: `var replaceOrdinals = function(o) {...}`. Whereas in this case, I only need one argument, so the `()` are not needed around the `o`. The `=>` is just part of the syntax, although it does do a couple of different things depending on if you use curly braces immediately after it. Those things are explained in that link. Does that answer your question? – KevBot Dec 11 '16 at 19:54
0

The solution in the answer by Kevbot is elegant, but its application is limited to ES6 browsers with an implementation of date.parse() that conforms to the specific date format used by the OP.

Instead of adding a library such as moment.js just to avoid the date.parse() dependency, a tailored solution that will work in any JavaScript environment (including old browsers) can be made with just a few lines of code:

var dates = [
  {'August 17th 2016': [75]}, 
  {'August 1st 2016': [5]}, 
  {'August 28th 2016': [5]}
];

dates.sort(function(a, b){
  var i, j;
  for(i in a); //get datestring a
  for(j in b); //get datestring b;
  return MMMDDYYYYtoSortableNumber(i) -
    MMMDDYYYYtoSortableNumber(j);
});

console.log(dates);

// MMMDDYYYYtoSortableNumber() converts datestrings
// such as "April 5th 1969" to 19690405.
// Month name to digit approach adapted from 
// https://gist.github.com/atk/1053863
  
function MMMDDYYYYtoSortableNumber(datestring) {
  var mdy = datestring.match(/\w(\w\w)\D+(\d+)\D+(\d+)/);
  return mdy[3] * 10000 +
    '  anebarprayunulugepctovec'.search(mdy[1]) * 50 +
    mdy[2] * 1;
}

Please note that it might be safer to represent the datestrings as object values rather than object keys. They will then be easier to extract safely (and faster to access). E.g.

{label: 'August 17th 2016', data: [75]}, 
Community
  • 1
  • 1
Tomas Langkaas
  • 4,551
  • 2
  • 19
  • 34