Related
I have an array of objects in an array. Each object has a date field. Here is a method I wrote to retrieve the index of the object with the newest date, works fine:
GetIndexOfLatestDate()
{
var indexOfLatestDate:number = 0;
var maxDate:number = new Date(this.objArray[0].date).getTime();
for(var nIndex:number = 1; nIndex < this.m_objArray.length; nIndex++)
{
if(new Date(this.objArray[nIndex].date).getTime() > maxDate)
{
maxDate = new Date(this.objArray[nIndex].date).getTime();
indexOFLatestDate = nIndex;
}
}
return indexOfLatestDate;
}
How can this be written (much) more succinctly?
Thanks for any help.
I would suggest using the reduce function that javascript provides. This solution also doesn't loop through the array multiple times, and it calls new Date().getTime() once per date.
GetIndexOfLatestDate()
{
if (this.objectArr === null || this.objectArr.length === 0) {
return null;
}
return this.objectArr.reduce((accum, value, index) => {
const newDate = new Date(value.date).getTime();
return newDate > accum.maxDate ? {index, maxDate: newDate} : accum;
}, {index: 0, maxDate: new Date(this.objectArr[0].date).getTime()}).index;
}
if this looks too confusing, here is an expanded version that's easier to follow if you are new to the reduce function.
GetIndexOfLatestDate()
{
// check if object arr is empty
if (this.objectArr === null || this.objectArr.length === 0) {
return null;
}
// set default accumulator for first passthrough
const defaultAccum = {
index: 0,
maxDate: new Date(this.objectArr[0].date).getTime()
}
const maxValueWithIndex = this.objectArr.reduce((accum, value, index) => {
// set formatted date to prevent multiple Date() calls
const newDate = new Date(value.date).getTime();
// if the new date is larger than the current largest date, set
// the accumulator to the new largest date and its index
if (newDate > accum.maxDate)
accum = {
index: index,
maxDate: newDate
};
}
// return the current accumulator, i.e. the current largest date
return accum;
}, defaultAccum);
// return the index of the latest date
return maxValueWithIndex.index;
}
You can do this using built-in function like this
const array1 = [{date: '2/5/2021'}, {date: '3/11/2019'}, {date: '12/9/2022'}];
const dateArray = array1.map(({date}) => {return new Date(date)})
const maxDate = Math.max(...dateArray);
const indexMaxElem = dateArray.findIndex(dateObj => dateObj.getTime() === maxDate)
console.log(indexMaxElem)
It is less efficient though, since it needs to do multiple pass through the array
let dateArr = [];
objArray.forEach(item => {
// extract the dates from the source array to form new array
dateArr.push(objArray.date.getTime();
});
// find the maximum date in this array, which will have the same index
indexOfLatest = dateArr.findIndex(Math.max(...dateArr));
GetIndexOfLatestDate(objArray){
let max = objArray.reduce(function (a, b){ return new Date(a.date) > new
Date(b.date) ? a : b; });
return objArray.indexOf(max);
}
You can do it with a reduce, something like:
index = this.objArray.reduce((accum, value, index) => {
if(!accum){
accum = {
index,
maxDate: value.date
};
} else {
if(accum.maxDate.getTime() > value.date.getTime()){
accum = {
index,
maxDate: value.date
};
}
}
return accum;
}
}, null).index;
How can I sort this array by date (ISO 8601)?
var myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
Playground:
https://jsfiddle.net/4tUZt/
Sort Lexicographically:
As #kdbanman points out, ISO8601See General principles was designed for lexicographical sort. As such the ISO8601 string representation can be sorted like any other string, and this will give the expected order.
'2007-01-17T08:00:00Z' < '2008-01-17T08:00:00Z' === true
So you would implement:
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }
];
myArray.sort(function(a, b) {
return (a.date < b.date) ? -1 : ((a.date > b.date) ? 1 : 0);
});
Sort using JavaScript Date:
Older versions of WebKit and Internet Explorer do not support ISO 8601 dates, so you have to make a compatible date. It is supported by FireFox, and modern WebKit though See here for more information about Date.parse support JavaScript: Which browsers support parsing of ISO-8601 Date String with Date.parse
Here is a very good article for creating a Javascript ISO 8601 compatible date, which you can then sort like regular javascript dates.
http://webcloud.se/log/JavaScript-and-ISO-8601/
Date.prototype.setISO8601 = function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
}
Usage:
console.log(myArray.sort(sortByDate));
function sortByDate( obj1, obj2 ) {
var date1 = (new Date()).setISO8601(obj1.date);
var date2 = (new Date()).setISO8601(obj2.date);
return date2 > date1 ? 1 : -1;
}
Updated usage to include sorting technique credit #nbrooks
You can avoid creating of dates and by using the built–in lexicographic compare function String.prototype.localeCompare, rather than the ?: compound operator or other expressions:
var myArray = [
{name: 'oldest', date: '2007-01-17T08:00:00Z'},
{name: 'newest', date: '2011-01-28T08:00:00Z'},
{name: 'old', date: '2009-11-25T08:00:00Z'}
];
// Oldest first
console.log(
myArray.sort((a, b) => a.date.localeCompare(b.date))
);
// Newest first
console.log(
myArray.sort((a, b) => -a.date.localeCompare(b.date))
);
Be careful, the accepted answer now advises to sort our dates lexicographically.
However, this will only work if all your strings use the 'Z' or '+00' timezone (= UTC).
Date strings ending with 'Z' do satisfy ISO8601 standard, but all ISO8601 do not end with 'Z'.
Thus, to be fully ISO8601 compliant, you need to parse your strings with some Date library (e.g. Javascript Date or Moment.js), and compare these objects.
For this part, you can check Scott's answer that also covers browsers incompatible with ISO8601.
My simple example with Javascript Date (works on any not-too-old browser) :
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00+0100' },
{ name:'old', date:'2009-11-25T08:00:00-0100' }
];
myArray.sort(function(a, b) {
return new Date(a.date) - new Date(b.date);
});
Downside : This is slower than just comparing strings lexicographically.
More info about ISO8601 standard : here.
I'd go with this:
const myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
function byDate (a, b) {
if (a.date < b.date) return -1;
if (a.date > b.date) return 1;
return 0;
}
const newArray = myArray.sort(byDate);
console.clear();
console.dir(myArray);
console.dir(newArray);
http://jsfiddle.net/4tUZt/2/
$(document).ready(function()
{
var myArray = [ { name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }];
console.log( myArray.sort(sortByDate) );
});
// Stable, ascending sort (use < for descending)
function sortByDate( obj1, obj2 ) {
return new Date(obj2.date) > new Date(obj1.date) ? 1 : -1;
}
Demo: http://jsfiddle.net/4tUZt/4/
var myArray = new Array();
myArray[0] = { name:'oldest', date: '2007-01-17T08:00:00Z' };
myArray[1] = { name:'newest', date: '2011-01-28T08:00:00Z' };
myArray[2] = { name:'old', date: '2009-11-25T08:00:00Z' };
var sortFunction = function (a, b) {
return Date.parse(b.date) - Date.parse(a.date);
};
/* or
var sortFunction = function (a, b) {
return new Date(b.date) - new Date(a.date);
};
*/
console.log(myArray.sort(sortFunction));
ISO8601 is designed to sort correctly as plain text, so in general, a normal sort will do.
To sort by a specific key of objects in an array, you need to specify a comparison function to the sort() method. In many other languages, these are easy to write using the cmp function, but JS doesn't have a built in cmp function, so I find it easiest to write my own.
var myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
// cmp helper function - built in to many other languages
var cmp = function (a, b) {
return (a > b) ? 1 : ( (a > b) ? -1 : 0 );
}
myArray.sort(function (a,b) { return cmp(a.date, b.date) });
P.s. I would write my array using JSON-like syntax, like this:
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }
];
In the instance that you're sorting objects that may be missing a date, and dates may be in different timezones, you'll end up needing something a little more complex:
const deletionDateSortASC = (itemA, itemB) =>
(+new Date(itemA.deletedAt) || 0) -
(+new Date(itemB.deletedAt) || 0);
const deletionDateSortDESC = (itemA, itemB) =>
deletionDateSortASC(itemB, itemA);
If you know the dates are all defined and valid, and you know that all the dates are in the same timezone, then you should pick one of the other faster answers. However, if you want date sorting, have one or more of these edge cases, and don't want to have to preprocess the data to clean it up, then I suggest this approach.
I tried to demonstrate in the snippet below how the other answers fail in these edge cases.
const data = [
{deletedAt: null},
{deletedAt: '2022-08-24T12:00:00Z'},
{deletedAt: undefined},
{deletedAt: '2015-01-01T00:00:00Z'},
{deletedAt: '2022-08-24T12:00:00-01:00'},
{deletedAt: '2022-08-24T12:00:00+01:00'},
{deletedAt: '2022-08-20T12:00:00+01:00'},
{deletedAt: undefined}
];
const deletionDateSortASC = (itemA, itemB) =>
(+new Date(itemA.deletedAt) || 0) -
(+new Date(itemB.deletedAt) || 0);
const deletionDateSortDESC = (itemA, itemB) =>
deletionDateSortASC(itemB, itemA);
function acceptedAnswerSortASC(a, b) {
return (a.deletedAt < b.deletedAt) ? -1 : ((a.deletedAt > b.deletedAt) ? 1 : 0);
}
function acceptedAnswerSortDESC(a, b) {
return acceptedAnswerSortASC(b, a);
}
// Had to modify this solution to avoid the TypeError: a.deletedAt is null
const localeCompareSortASC = (a, b) => (a.deletedAt || '').localeCompare(b.deletedAt);
const localeCompareSortDESC = (a, b) => -(a.deletedAt || '').localeCompare(b.deletedAt);
function simpleDateSubtractionSortASC(a, b) {
return new Date(a.deletedAt) - new Date(b.deletedAt);
}
function simpleDateSubtractionSortDESC(a, b) {
return simpleDateSubtractionSortASC(b, a);
}
console.log('Using modified Date subtraction', [...data].sort(deletionDateSortDESC));
console.log('Using accepted answer lexocographical sort', [...data].sort(acceptedAnswerSortDESC));
console.log('Using locale compare lexocographical sort', [...data].sort(localeCompareSortDESC));
console.log('Using simple Date subtraction sort', [...data].sort(simpleDateSubtractionSortDESC));
I want to sort an array based on an sort order.
public array1: Array<string> = [];
array.push(some string values); //E.g dog,apple,man
I have a sort order like
dog = 1
apple = 3
man = 2
So i want to sort this array like dog,man,apple.
How to do this in typescript.
If you'd have your order in a map(object) you could just do this.
let list = ['dog', 'cat','apple'];
let sortOrder = {
dog: 1,
cat: 3,
apple: 2
}
list.sort((a, b) => sortOrder[a] - sortOrder[b]);
You can see a working playground example here.
I suppose you use TypeScript (as tagged in you question).
let data = [
{value:"dog", key:1},
{value:"apple", key:3},
{value:"man", key:2},
];
data.sort((d1, d2) => {
if (d1.key > d2.key) return 1;
if (d1.key < d2.key) return -1;
return 0;
});
You have enhanced your question then this answer is not relevant anymore (and fixed code as mentioned in comments).
This will also work. Source.
randomizeArray(a, b, c, d) { // array, placeholder, placeholder, placeholder
c = a.length; while (c) b = Math.random() * c-- | 0, d = a[c], a[c] = a[b], a[b] = d
}
And you can call this function this way, where data is an array []
this.randomizeArray(data, null, null, null);
I have a service/factory that takes an array of dates, and group it in an array of arrays [[],[]] according to ISO weeks. This feature works as expected.
But how can I extend the service/factory to take another array of values (just normal integer values), and create a key-value pair of each date and value. Still in the same output format of an array of arrays?
This is my service/factory call:
$scope.weeks = GroupDateRangeService.createArray(timeline_data, time_trend);
The data that is passed to the service would look like this:
timeline_data: ["2017-01-04","2017-01-05","2017-01-06","2017-01-07","2017-01-08","2017-01-09","2017-01-10","2017-01-11"]
time_trend: [566, 607, 430, 357, 277, 591, 711, 206]
The result would look something like this:
result: [["2017-01-04": 566,"2017-01-05": 607,"2017-01-06": 430,"2017-01-07": 357,"2017-01-08": 277], ["2017-01-09": 591,"2017-01-10": 711,"2017-01-11": 206]]
This is my service/factory:
(function () {
'use strict';
angular
.module('portalDashboardApp')
.factory('GroupDateRangeService', GroupDateRangeService);
GroupDateRangeService.$inject = [];
function GroupDateRangeService() {
var service = {
createArray: createArray,
};
return service;
function createArray(data) {
var arr = data.map(function (s) {
var week = getWeekNumber(parseISOLocal(s));
return week[0] + ('0' + week[1]).slice(-2) + ':' + s;
}).sort();
return createGroupedArray(createGroupObject(arr));
};
function createGroupObject(arr) {
var groupedObj = arr.reduce(function (result, value) {
var b = value.split(':');
if (!result[b[0]]) result[b[0]] = [];
result[b[0]].push(b[1]);
return result;
}, {});
return groupedObj;
};
function createGroupedArray(groupedObj) {
// Grab arrays in order of week number. Sort keys to maintain order
var groupedArray = Object.keys(groupedObj).sort().map(key=>groupedObj[key]);
return groupedArray;
}
/* Helper to get the ISO week number of a date
** #param {Date} date to get week of
** #returns {Array} [year, weekNumber]
*/
function getWeekNumber(d) {
d = new Date(+d);
d.setHours(0, 0, 0, 0);
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
var yearStart = new Date(d.getFullYear(), 0, 1);
var weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
return [d.getFullYear(), weekNo];
}
/* Parse ISO 8601 format date string to local date
** #param {string} s - string to parse like 2016-12-15
** #returns {Date}
*/
function parseISOLocal(s) {
var b = s.split(/\D/);
return new Date(b[0], b[1] - 1, b[2]);
}
}
})();
I would appreciate your guidance!
Your result cannot look like that, an array cannot have key-value pairs. It will have to be an array of array of objects. If you refactor your function to take a second argument you can do the following :
function createArray(data, optionalTimeTrend) {
var arr = data.map(function (s) {
var week = getWeekNumber(parseISOLocal(s));
return week[0] + ('0' + week[1]).slice(-2) + ':' + s;
}).sort();
var results = createGroupedArray(createGroupObject(arr));
if (optionalTimeTrend && optionalTimeTrend.length === data.length) {
for (var i = 0; i < results.length; i++) {
results[i] = results[i].map(function (date, index) {
var obj = {};
obj[date] = optionalTimeTrend[index];
return obj;
});
}
}
return results;
};
Your results should look like this then :
result: [[{"2017-01-04": 566},{"2017-01-05": 607},{"2017-01-06": 430},{"2017-01-07": 357},{"2017-01-08": 277}], [{"2017-01-09": 591},{"2017-01-10": 711},{"2017-01-11": 206}]]
Think this is your merge routine here (updated to show how to use internal vs. provided arrays, and how to switch processing instructions):
// These arrays were already made by your service
let premadeKeys = [ 'pre', 'made', 'keys' ];
let premadeVals = [ 'val1', 'val2', 'val3' ];
// Formatrules is a naive way to switch how you want it processed, could be any enum etc.
function mergeArrays ( keys = premadeKeys, values = premadeVals, formatRules = 0 ) {
switch ( formatRules ) {
case 0:
return keys.map ( ( d, i ) => {
let obj = {};
obj [ d ] = values [ i ];
return obj;
} );
case 1:
return keys.map ( ( d, i ) => {
let obj = {};
obj [ d ] = values [ i ] + '_TAIL_' + i;
return obj;
} );
}
}
let arr1 = [ "a", "b", "c" ];
let arr2 = [ 1, 2, 3 ];
// provided arrays
console.log ( mergeArrays ( arr1, arr2 ) );
console.log ( mergeArrays ( arr1, arr2, 1 ) );
// pre made arrays
console.log ( mergeArrays ( ) );
console.log ( mergeArrays ( undefined, undefined, 1 ) );
How can I sort this array by date (ISO 8601)?
var myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
Playground:
https://jsfiddle.net/4tUZt/
Sort Lexicographically:
As #kdbanman points out, ISO8601See General principles was designed for lexicographical sort. As such the ISO8601 string representation can be sorted like any other string, and this will give the expected order.
'2007-01-17T08:00:00Z' < '2008-01-17T08:00:00Z' === true
So you would implement:
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }
];
myArray.sort(function(a, b) {
return (a.date < b.date) ? -1 : ((a.date > b.date) ? 1 : 0);
});
Sort using JavaScript Date:
Older versions of WebKit and Internet Explorer do not support ISO 8601 dates, so you have to make a compatible date. It is supported by FireFox, and modern WebKit though See here for more information about Date.parse support JavaScript: Which browsers support parsing of ISO-8601 Date String with Date.parse
Here is a very good article for creating a Javascript ISO 8601 compatible date, which you can then sort like regular javascript dates.
http://webcloud.se/log/JavaScript-and-ISO-8601/
Date.prototype.setISO8601 = function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
}
Usage:
console.log(myArray.sort(sortByDate));
function sortByDate( obj1, obj2 ) {
var date1 = (new Date()).setISO8601(obj1.date);
var date2 = (new Date()).setISO8601(obj2.date);
return date2 > date1 ? 1 : -1;
}
Updated usage to include sorting technique credit #nbrooks
You can avoid creating of dates and by using the built–in lexicographic compare function String.prototype.localeCompare, rather than the ?: compound operator or other expressions:
var myArray = [
{name: 'oldest', date: '2007-01-17T08:00:00Z'},
{name: 'newest', date: '2011-01-28T08:00:00Z'},
{name: 'old', date: '2009-11-25T08:00:00Z'}
];
// Oldest first
console.log(
myArray.sort((a, b) => a.date.localeCompare(b.date))
);
// Newest first
console.log(
myArray.sort((a, b) => -a.date.localeCompare(b.date))
);
Be careful, the accepted answer now advises to sort our dates lexicographically.
However, this will only work if all your strings use the 'Z' or '+00' timezone (= UTC).
Date strings ending with 'Z' do satisfy ISO8601 standard, but all ISO8601 do not end with 'Z'.
Thus, to be fully ISO8601 compliant, you need to parse your strings with some Date library (e.g. Javascript Date or Moment.js), and compare these objects.
For this part, you can check Scott's answer that also covers browsers incompatible with ISO8601.
My simple example with Javascript Date (works on any not-too-old browser) :
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00+0100' },
{ name:'old', date:'2009-11-25T08:00:00-0100' }
];
myArray.sort(function(a, b) {
return new Date(a.date) - new Date(b.date);
});
Downside : This is slower than just comparing strings lexicographically.
More info about ISO8601 standard : here.
I'd go with this:
const myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
function byDate (a, b) {
if (a.date < b.date) return -1;
if (a.date > b.date) return 1;
return 0;
}
const newArray = myArray.sort(byDate);
console.clear();
console.dir(myArray);
console.dir(newArray);
http://jsfiddle.net/4tUZt/2/
$(document).ready(function()
{
var myArray = [ { name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }];
console.log( myArray.sort(sortByDate) );
});
// Stable, ascending sort (use < for descending)
function sortByDate( obj1, obj2 ) {
return new Date(obj2.date) > new Date(obj1.date) ? 1 : -1;
}
Demo: http://jsfiddle.net/4tUZt/4/
var myArray = new Array();
myArray[0] = { name:'oldest', date: '2007-01-17T08:00:00Z' };
myArray[1] = { name:'newest', date: '2011-01-28T08:00:00Z' };
myArray[2] = { name:'old', date: '2009-11-25T08:00:00Z' };
var sortFunction = function (a, b) {
return Date.parse(b.date) - Date.parse(a.date);
};
/* or
var sortFunction = function (a, b) {
return new Date(b.date) - new Date(a.date);
};
*/
console.log(myArray.sort(sortFunction));
ISO8601 is designed to sort correctly as plain text, so in general, a normal sort will do.
To sort by a specific key of objects in an array, you need to specify a comparison function to the sort() method. In many other languages, these are easy to write using the cmp function, but JS doesn't have a built in cmp function, so I find it easiest to write my own.
var myArray = new Array();
myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old', date:'2009-11-25T08:00:00Z' }
// cmp helper function - built in to many other languages
var cmp = function (a, b) {
return (a > b) ? 1 : ( (a > b) ? -1 : 0 );
}
myArray.sort(function (a,b) { return cmp(a.date, b.date) });
P.s. I would write my array using JSON-like syntax, like this:
var myArray = [
{ name:'oldest', date:'2007-01-17T08:00:00Z' },
{ name:'newest', date:'2011-01-28T08:00:00Z' },
{ name:'old', date:'2009-11-25T08:00:00Z' }
];
In the instance that you're sorting objects that may be missing a date, and dates may be in different timezones, you'll end up needing something a little more complex:
const deletionDateSortASC = (itemA, itemB) =>
(+new Date(itemA.deletedAt) || 0) -
(+new Date(itemB.deletedAt) || 0);
const deletionDateSortDESC = (itemA, itemB) =>
deletionDateSortASC(itemB, itemA);
If you know the dates are all defined and valid, and you know that all the dates are in the same timezone, then you should pick one of the other faster answers. However, if you want date sorting, have one or more of these edge cases, and don't want to have to preprocess the data to clean it up, then I suggest this approach.
I tried to demonstrate in the snippet below how the other answers fail in these edge cases.
const data = [
{deletedAt: null},
{deletedAt: '2022-08-24T12:00:00Z'},
{deletedAt: undefined},
{deletedAt: '2015-01-01T00:00:00Z'},
{deletedAt: '2022-08-24T12:00:00-01:00'},
{deletedAt: '2022-08-24T12:00:00+01:00'},
{deletedAt: '2022-08-20T12:00:00+01:00'},
{deletedAt: undefined}
];
const deletionDateSortASC = (itemA, itemB) =>
(+new Date(itemA.deletedAt) || 0) -
(+new Date(itemB.deletedAt) || 0);
const deletionDateSortDESC = (itemA, itemB) =>
deletionDateSortASC(itemB, itemA);
function acceptedAnswerSortASC(a, b) {
return (a.deletedAt < b.deletedAt) ? -1 : ((a.deletedAt > b.deletedAt) ? 1 : 0);
}
function acceptedAnswerSortDESC(a, b) {
return acceptedAnswerSortASC(b, a);
}
// Had to modify this solution to avoid the TypeError: a.deletedAt is null
const localeCompareSortASC = (a, b) => (a.deletedAt || '').localeCompare(b.deletedAt);
const localeCompareSortDESC = (a, b) => -(a.deletedAt || '').localeCompare(b.deletedAt);
function simpleDateSubtractionSortASC(a, b) {
return new Date(a.deletedAt) - new Date(b.deletedAt);
}
function simpleDateSubtractionSortDESC(a, b) {
return simpleDateSubtractionSortASC(b, a);
}
console.log('Using modified Date subtraction', [...data].sort(deletionDateSortDESC));
console.log('Using accepted answer lexocographical sort', [...data].sort(acceptedAnswerSortDESC));
console.log('Using locale compare lexocographical sort', [...data].sort(localeCompareSortDESC));
console.log('Using simple Date subtraction sort', [...data].sort(simpleDateSubtractionSortDESC));