how to sort string data by date? [duplicate] - javascript
Say I have an array of a few objects:
var array = [{id: 1, date: Mar 12 2012 10:00:00 AM}, {id: 2, date: Mar 8 2012 08:00:00 AM}];
How can I sort this array by the date element in order from the date closest to the current date and time down? Keep in mind that the array may have many objects, but for the sake of simplicity I used 2.
Would I use the sort function and a custom comparator?
Simplest Answer
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);
});
More Generic Answer
array.sort(function(o1,o2){
if (sort_o1_before_o2) return -1;
else if(sort_o1_after_o2) return 1;
else return 0;
});
Or more tersely:
array.sort(function(o1,o2){
return sort_o1_before_o2 ? -1 : sort_o1_after_o2 ? 1 : 0;
});
Generic, Powerful Answer
Define a custom non-enumerable sortBy function using a Schwartzian transform on all arrays :
(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 it like so:
array.sortBy(function(o){ return o.date });
If your date is not directly comparable, make a comparable date out of it, e.g.
array.sortBy(function(o){ return new Date( o.date ) });
You can also use this to sort by multiple criteria if you return an array of values:
// Sort by date, then score (reversed), then name
array.sortBy(function(o){ return [ o.date, -o.score, o.name ] };
See http://phrogz.net/JS/Array.prototype.sortBy.js for more details.
#Phrogz answers are both great, but here is a great, more concise answer:
array.sort(function(a,b){return a.getTime() - b.getTime()});
Using the arrow function way
array.sort((a,b)=>a.getTime()-b.getTime());
found here: Sort date in Javascript
After correcting the JSON this should work for you now:
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;
});
Your data needs some corrections:
var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];
After correcting the data, you can use this piece of code:
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);β
Above answers are all good π, here is my implementation of sorting date in ES6 way, I'm using Date.parse (is global Date object) this will convert string representation of Date to number of milliseconds. Instead of instantiating new Date object every time.
var array = ["2021-08-10T07:24:30.087+0000" , "2021-09-30T07:24:30.087+0000", "2021-10-13T07:24:30.087+0000"];
// sorting with latest date
array.sort((a,b) => Date.parse(b) - Date.parse(a))
I recommend GitHub: Array sortBy - a best implementation of sortBy method which uses the Schwartzian transform
But for now we are going to try this approach Gist: sortBy-old.js.
Let's create a method to sort arrays being able to arrange objects by some property.
Creating the sorting function
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));
});
};
}());
Setting unsorted data
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"}
];
Using it
Finally, we arrange the array, by "date" property as string
//sort the object by a property (ascending)
//sorting takes into account uppercase and lowercase
sortBy(data, { prop: "date" });
If you want to ignore letter case, set the "parser" callback:
//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();
}
});
If you want to treat the "date" field as Date type:
//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);
}
});
Here you can play with the above example:
jsbin.com/lesebi
This should do when your date is in this format (dd/mm/yyyy).
sortByDate(arr) {
arr.sort(function(a,b){
return Number(new Date(a.readableDate)) - Number(new Date(b.readableDate));
});
return arr;
}
Then call sortByDate(myArr);
arr is an array of object and each object has date_prop which is a date. You can sort it in descending/decreasing order like this
arr = arr.sort(function (a, b) {
var dateA = new Date(a.date_prop).getTime();
var dateB = new Date(b.date_prop).getTime();
return dateA < dateB ? 1 : -1; // ? -1 : 1 for ascending/increasing order
});
You could use sortBy in underscore js.
http://underscorejs.org/#sortBy
Sample:
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'));
With ES6 arrow functions, you can further write just one line of concise code (excluding variable declaration).
Eg.:
var isDescending = true; //set to false for ascending
console.log(["8/2/2020","8/1/2020","8/13/2020", "8/2/2020"].sort((a,b) => isDescending ? new Date(b).getTime() - new Date(a).getTime() : new Date(a).getTime() - new Date(b).getTime()));
Since time does not exists with the above dates, the Date object will consider following default time for sorting:
00:00:00
The code will work for both ascending and descending sort.
Just change the value of isDescending variable as required.
Strings with dates are comparable in JavaScript (if they are syntactically the same), e.g.:
'2020-12-01' < '2020-12-02' == true
This means you can use this expression in a custom sort function:
var arr = [{id:1, date:'2020-12-01'}, {id:1, date:'2020-12-15'}, {id:1, date:'2020-12-12'}]
function sortByDate(a, b) {
if (a.date < b.date) {
return 1;
}
if (a.date > b.date) {
return -1;
}
return 0;
}
const sorted = arr.sort(sortByDate);
console.log(sorted);
I'm going to add this here, as some uses may not be able to work out how to invert this sorting method.
To sort by 'coming up', we can simply swap a & b, like so:
your_array.sort ( (a, b) => {
return new Date(a.DateTime) - new Date(b.DateTime);
});
Notice that a is now on the left hand side, and b is on the right, :D!
i was able to achieve sorting using below lines:
array.sort(function(a, b)
{
if (a.DueDate > b.DueDate) return 1;
if (a.DueDate < b.DueDate) return -1;
})
I personally use following approach to sort dates.
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;
})
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))
});
Here is the shortest way to solve your problem.
var array = [{id: 1, date: 'Mar 12 2012 10:00:00 AM'}, {id: 2, date: 'Mar 8 2012 08:00:00 AM'}];
var sortedArray = array.sort((a,b) => Date.parse(new Date(a.date)) - Date.parse(new Date(b.date)));
Thank you Ganesh Sanap. sorting items by date field from old to new. Use it
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;
});
Simple one line solution for me to sort dates :
sort((a, b) => (a < b ? 1 : -1))
["12 Jan 2018" , "1 Dec 2018", "04 May 2018"].sort(function(a,b) {
return new Date(a).getTime() - new Date(b).getTime()
})
For anyone who is wanting to sort by date (UK format), I used the following:
//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;
});
}
I have just taken the Schwartzian transform depicted above and made as function. It takes an array, the sorting function and a boolean as input:
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));
If like me you have an array with dates formatted like YYYY[-MM[-DD]] where you'd like to order more specific dates before less specific ones, I came up with this handy function:
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)
}
Thanks for those brilliant answers on top. I have thought a slightly complicated answer. Just for those who want to compare different answers.
const data = [
'2-2018', '1-2018',
'3-2018', '4-2018',
'1-2019', '2-2019',
'3-2019', '4-2019',
'1-2020', '3-2020',
'4-2020', '1-2021'
]
let eachYearUniqueMonth = data.reduce((acc, elem) => {
const uniqueDate = Number(elem.match(/(\d+)\-(\d+)/)[1])
const uniqueYear = Number(elem.match(/(\d+)\-(\d+)/)[2])
if (acc[uniqueYear] === undefined) {
acc[uniqueYear] = []
} else{
if (acc[uniqueYear] && !acc[uniqueYear].includes(uniqueDate)) {
acc[uniqueYear].push(uniqueDate)
}
}
return acc;
}, {})
let group = Object.keys(eachYearUniqueMonth).reduce((acc,uniqueYear)=>{
eachYearUniqueMonth[uniqueYear].forEach(uniqueMonth=>{
acc.push(`${uniqueYear}-${uniqueMonth}`)
})
return acc;
},[])
console.log(group); //["2018-1", "2018-3", "2018-4", "2019-2", "2019-3", "2019-4", "2020-3", "2020-4"]
I have an array of objects in which key 'time' contains the date in ISO format
Example - 2021-12-24T11:02:20.370705
arr.sort(function(a,b){return a.time > b.time ? 1 : a.time < b.time ? -1 : 0 });
Above worked for me like a charm!
If you are into MongoDB, one of the solutions is:
db.collection.find({}).sort("your date field");
For example:
db.collection.find({}).sort("createdAt");
Related
Sorting by date in a rsuite table - ReactJS [duplicate]
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));
JavaScript: How to sort array of objects by two object properties? [duplicate]
I have a multidimensional array. The primary array is an array of [publicationID][publication_name][ownderID][owner_name] What I am trying to do is sort the array by owner_name and then by publication_name. I know in JavaScript you have Array.sort(), into which you can put a custom function, in my case i have: function mysortfunction(a, b) { var x = a[3].toLowerCase(); var y = b[3].toLowerCase(); return ((x < y) ? -1 : ((x > y) ? 1 : 0)); } This is fine for just sorting on the one column, namely owner_name, but how do I modify it to sort on owner_name, then publication_name?
If owner names differ, sort by them. Otherwise, use publication name for tiebreaker. function mysortfunction(a, b) { var o1 = a[3].toLowerCase(); var o2 = b[3].toLowerCase(); var p1 = a[1].toLowerCase(); var p2 = b[1].toLowerCase(); if (o1 < o2) return -1; if (o1 > o2) return 1; if (p1 < p2) return -1; if (p1 > p2) return 1; return 0; }
I think what you're looking for is thenBy.js: https://github.com/Teun/thenBy.js It allows you to use the standard Array.sort, but with firstBy().thenBy().thenBy() style. An example can be seen here.
A good way to sort on many fields that are strings is to use toLocaleCompare and the boolean operator ||. Something like: // Sorting record releases by name and then by title. releases.sort((oldRelease, newRelease) => { const compareName = oldRelease.name.localeCompare(newRelease.name); const compareTitle = oldRelease.title.localeCompare(newRelease.title); return compareName || compareTitle; }) If you wanted to sort on more fields, you could simply chain them off the return statement with more boolean operators.
Came across a need to do SQL-style mixed asc and desc object array sorts by keys. kennebec's solution above helped me get to this: Array.prototype.keySort = function(keys) { keys = keys || {}; // via // https://stackoverflow.com/questions/5223/length-of-javascript-object-ie-associative-array var obLen = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; // avoiding using Object.keys because I guess did it have IE8 issues? // else var obIx = function(obj, ix){ return Object.keys(obj)[ix]; } or // whatever var obIx = function(obj, ix) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) { if (size == ix) return key; size++; } } return false; }; var keySort = function(a, b, d) { d = d !== null ? d : 1; // a = a.toLowerCase(); // this breaks numbers // b = b.toLowerCase(); if (a == b) return 0; return a > b ? 1 * d : -1 * d; }; var KL = obLen(keys); if (!KL) return this.sort(keySort); for ( var k in keys) { // asc unless desc or skip keys[k] = keys[k] == 'desc' || keys[k] == -1 ? -1 : (keys[k] == 'skip' || keys[k] === 0 ? 0 : 1); } this.sort(function(a, b) { var sorted = 0, ix = 0; while (sorted === 0 && ix < KL) { var k = obIx(keys, ix); if (k) { var dir = keys[k]; sorted = keySort(a[k], b[k], dir); ix++; } } return sorted; }); return this; }; sample usage: var obja = [ {USER:"bob", SCORE:2000, TIME:32, AGE:16, COUNTRY:"US"}, {USER:"jane", SCORE:4000, TIME:35, AGE:16, COUNTRY:"DE"}, {USER:"tim", SCORE:1000, TIME:30, AGE:17, COUNTRY:"UK"}, {USER:"mary", SCORE:1500, TIME:31, AGE:19, COUNTRY:"PL"}, {USER:"joe", SCORE:2500, TIME:33, AGE:18, COUNTRY:"US"}, {USER:"sally", SCORE:2000, TIME:30, AGE:16, COUNTRY:"CA"}, {USER:"yuri", SCORE:3000, TIME:34, AGE:19, COUNTRY:"RU"}, {USER:"anita", SCORE:2500, TIME:32, AGE:17, COUNTRY:"LV"}, {USER:"mark", SCORE:2000, TIME:30, AGE:18, COUNTRY:"DE"}, {USER:"amy", SCORE:1500, TIME:29, AGE:19, COUNTRY:"UK"} ]; var sorto = { SCORE:"desc",TIME:"asc", AGE:"asc" }; obja.keySort(sorto); yields the following: 0: { USER: jane; SCORE: 4000; TIME: 35; AGE: 16; COUNTRY: DE; } 1: { USER: yuri; SCORE: 3000; TIME: 34; AGE: 19; COUNTRY: RU; } 2: { USER: anita; SCORE: 2500; TIME: 32; AGE: 17; COUNTRY: LV; } 3: { USER: joe; SCORE: 2500; TIME: 33; AGE: 18; COUNTRY: US; } 4: { USER: sally; SCORE: 2000; TIME: 30; AGE: 16; COUNTRY: CA; } 5: { USER: mark; SCORE: 2000; TIME: 30; AGE: 18; COUNTRY: DE; } 6: { USER: bob; SCORE: 2000; TIME: 32; AGE: 16; COUNTRY: US; } 7: { USER: amy; SCORE: 1500; TIME: 29; AGE: 19; COUNTRY: UK; } 8: { USER: mary; SCORE: 1500; TIME: 31; AGE: 19; COUNTRY: PL; } 9: { USER: tim; SCORE: 1000; TIME: 30; AGE: 17; COUNTRY: UK; } keySort: { } (using a print function from here) here is a jsbin example. edit: cleaned up and posted as mksort.js on github.
This is handy for alpha sorts of all sizes. Pass it the indexes you want to sort by, in order, as arguments. Array.prototype.deepSortAlpha= function(){ var itm, L=arguments.length, order=arguments; var alphaSort= function(a, b){ a= a.toLowerCase(); b= b.toLowerCase(); if(a== b) return 0; return a> b? 1:-1; } if(!L) return this.sort(alphaSort); this.sort(function(a, b){ var tem= 0, indx=0; while(tem==0 && indx<L){ itm=order[indx]; tem= alphaSort(a[itm], b[itm]); indx+=1; } return tem; }); return this; } var arr= [[ "Nilesh","Karmshil"], ["Pranjal","Deka"], ["Susants","Ghosh"], ["Shiv","Shankar"], ["Javid","Ghosh"], ["Shaher","Banu"], ["Javid","Rashid"]]; arr.deepSortAlpha(1,0);
I suggest to use a built in comparer and chain the wanted sort order with logical or ||. function customSort(a, b) { return a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]); } Working example: var array = [ [0, 'Aluminium', 0, 'Francis'], [1, 'Argon', 1, 'Ada'], [2, 'Brom', 2, 'John'], [3, 'Cadmium', 3, 'Marie'], [4, 'Fluor', 3, 'Marie'], [5, 'Gold', 1, 'Ada'], [6, 'Kupfer', 4, 'Ines'], [7, 'Krypton', 4, 'Joe'], [8, 'Sauerstoff', 3, 'Marie'], [9, 'Zink', 5, 'Max'] ]; array.sort(function (a, b) { return a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]); }); document.write('<pre>'); array.forEach(function (a) { document.write(JSON.stringify(a) + '<br>'); });
You could concat the 2 variables together into a sortkey and use that for your comparison. list.sort(function(a,b){ var aCat = a.var1 + a.var2; var bCat = b.var1 + b.var2; return (aCat > bCat ? 1 : aCat < bCat ? -1 : 0); });
I found multisotr. This is simple, powerfull and small library for multiple sorting. I was need to sort an array of objects with dynamics sorting criteria: const criteria = ['name', 'speciality'] const data = [ { name: 'Mike', speciality: 'JS', age: 22 }, { name: 'Tom', speciality: 'Java', age: 30 }, { name: 'Mike', speciality: 'PHP', age: 40 }, { name: 'Abby', speciality: 'Design', age: 20 }, ] const sorted = multisort(data, criteria) console.log(sorted) <script src="https://cdn.rawgit.com/peterkhayes/multisort/master/multisort.js"></script> This library more mutch powerful, that was my case. Try it.
String Appending Method You can sort by multiple values simply by appending the values into a string and comparing the strings. It is helpful to add a split key character to prevent runoff from one key to the next. Example const arr = [ { a: 1, b: 'a', c: 3 }, { a: 2, b: 'a', c: 5 }, { a: 1, b: 'b', c: 4 }, { a: 2, b: 'a', c: 4 } ] function sortBy (arr, keys, splitKeyChar='~') { return arr.sort((i1,i2) => { const sortStr1 = keys.reduce((str, key) => str + splitKeyChar+i1[key], '') const sortStr2 = keys.reduce((str, key) => str + splitKeyChar+i2[key], '') return sortStr1.localeCompare(sortStr2) }) } console.log(sortBy(arr, ['a', 'b', 'c'])) Recursion Method You can also use Recursion to do this. It is a bit more complex than the String Appending Method but it allows you to do ASC and DESC on the key level. I'm commenting on each section as it is a bit more complex. There are a few commented out tests to show and verify the sorting works with a mixture of order and default order. Example const arr = [ { a: 1, b: 'a', c: 3 }, { a: 2, b: 'a', c: 5 }, { a: 1, b: 'b', c: 4 }, { a: 2, b: 'a', c: 4 } ] function sortBy (arr, keys) { return arr.sort(function sort (i1,i2, sKeys=keys) { // Get order and key based on structure const compareKey = (sKeys[0].key) ? sKeys[0].key : sKeys[0]; const order = sKeys[0].order || 'ASC'; // ASC || DESC // Calculate compare value and modify based on order let compareValue = i1[compareKey].toString().localeCompare(i2[compareKey].toString()) compareValue = (order.toUpperCase() === 'DESC') ? compareValue * -1 : compareValue // See if the next key needs to be considered const checkNextKey = compareValue === 0 && sKeys.length !== 1 // Return compare value return (checkNextKey) ? sort(i1, i2, sKeys.slice(1)): compareValue; }) } // console.log(sortBy(arr, ['a', 'b', 'c'])) console.log(sortBy(arr, [{key:'a',order:'desc'}, 'b', 'c'])) // console.log(sortBy(arr, ['a', 'b', {key:'c',order:'desc'}])) // console.log(sortBy(arr, ['a', {key:'b',order:'desc'}, 'c'])) // console.log(sortBy(arr, [{key:'a',order:'asc'}, {key:'b',order:'desc'}, {key:'c',order:'desc'}]))
Try this: t.sort( (a,b)=> a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]) ); let t = [ //[publicationID, publication_name, ownderID, owner_name ] [1, 'ZBC', 3, 'John Smith'], [2, 'FBC', 5, 'Mike Tyson'], [3, 'ABC', 7, 'Donald Duck'], [4, 'DBC', 1, 'Michael Jackson'], [5, 'XYZ', 2, 'Michael Jackson'], [6, 'BBC', 4, 'Michael Jackson'], ]; // owner_name subarrray index = 3 // publication_name subarrray index = 1 t.sort( (a,b)=> a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]) ); console.log(t.join('\n')); I assume that your data in array let t = [ [publicationID, publication_name, ownderID, owner_name ], ... ] where index of owner_name = 3 and publication_name =1.
I was working with ng-grid and needed to to multiple column sorting on an array of records returned from an API, so I came up with this nifty, dynamic multi-sort function. First of all, ng-grid fires an "event" for "ngGridSorted" and passes this structure back, describing the sort: sortData = { columns: DOM Element, directions: [], //Array of string values desc or asc. Each index relating to the same index of fields fields: [], //Array of string values }; So I built a function that will dynamically generate a sort function based on the sortData as shown above (Don't be scared by the scroll bar! It's only about 50 lines long! Also, I'm sorry about the slop. It prevented a horizontal scrollbar!): function SortingFunction(sortData) { this.sortData = sortData; this.sort = function(a, b) { var retval = 0; if(this.sortData.fields.length) { var i = 0; /* Determine if there is a column that both entities (a and b) have that are not exactly equal. The first one that we find will be the column we sort on. If a valid column is not located, then we will return 0 (equal). */ while( ( !a.hasOwnProperty(this.sortData.fields[i]) || !b.hasOwnProperty(this.sortData.fields[i]) || (a.hasOwnProperty(this.sortData.fields[i]) && b.hasOwnProperty(this.sortData.fields[i]) && a[this.sortData.fields[i]] === b[this.sortData.fields[i]]) ) && i < this.sortData.fields.length){ i++; } if(i < this.sortData.fields.length) { /* A valid column was located for both entities in the SortData. Now perform the sort. */ if(this.sortData.directions && i < this.sortData.directions.length && this.sortData.directions[i] === 'desc') { if(a[this.sortData.fields[i]] > b[this.sortData.fields[i]]) retval = -1; else if(a[this.sortData.fields[i]] < b[this.sortData.fields[i]]) retval = 1; } else { if(a[this.sortData.fields[i]] < b[this.sortData.fields[i]]) retval = -1; else if(a[this.sortData.fields[i]] > b[this.sortData.fields[i]]) retval = 1; } } } return retval; }.bind(this); } I then sort the results of my API (results) like so: results.sort(new SortingFunction(sortData).sort); I hope somebody else enjoys this solution as much as I do! Thanks!
I had a similar problem while displaying memory pool blocks from the output of some virtual DOM h-functions composition. Basically I faced to the same problem as sorting multi-criteria data like scoring results from players around the world. I have noticed that multi-criteria sorting is: - sort by the first column - if equal, sort by the second - if equal, sort by the third - etc... nesting and nesting if-else And if you don't care, you could fail quickly in a if-else nesting hell... like callback hell of promises... What about if we write a "predicate" function to decide if which part of alternative using ? The predicate is simply : // useful for chaining test const decide = (test, other) => test === 0 ? other : test Now after having written your classifying tests (byCountrySize, byAge, byGameType, byScore, byLevel...) whatever who need, you can weight your tests (1 = asc, -1 = desc, 0 = disable), put them in an array, and apply a reducing 'decide' function like this: const multisort = (s1, s2) => { const bcs = -1 * byCountrySize(s1, s2) // -1 = desc const ba = 1 *byAge(s1, s2) const bgt = 0 * byGameType(s1, s2) // 0 = doesn't matter const bs = 1 * byScore(s1, s2) const bl = -1 * byLevel(s1, s2) // -1 = desc // ... other weights and criterias // array order matters ! return [bcs, ba, bgt, bs, bl].reduce((acc, val) => decide(val, acc), 0) } // invoke [].sort with custom sort... scores.sort(multisort) And voila ! It's up to you to define your own criterias / weights / orders... but you get the idea. Hope this helps ! EDIT: * ensure that there is a total sorting order on each column * be aware of not having dependencies between columns orders, and no circular dependencies if, not, sorting can be unstable !
function multiSort() { var args =$.makeArray( arguments ), sortOrder=1, prop='', aa='', b=''; return function (a, b) { for (var i=0; i<args.length; i++){ if(args[i][0]==='-'){ prop=args[i].substr(1) sortOrder=-1 } else{sortOrder=1; prop=args[i]} aa = a[prop].toLowerCase() bb = b[prop].toLowerCase() if (aa < bb) return -1 * sortOrder; if (aa > bb) return 1 * sortOrder; } return 0 } } empArray.sort(multiSort( 'lastname','firstname')) Reverse with '-lastname'
My own library for working with ES6 iterables (blinq) allows (among other things) easy multi-level sorting const blinq = window.blinq.blinq // or import { blinq } from 'blinq' // or const { blinq } = require('blinq') const dates = [{ day: 1, month: 10, year: 2000 }, { day: 1, month: 1, year: 2000 }, { day: 2, month: 1, year: 2000 }, { day: 1, month: 1, year: 1999 }, { day: 1, month: 1, year: 2000 } ] const sortedDates = blinq(dates) .orderBy(x => x.year) .thenBy(x => x.month) .thenBy(x => x.day); console.log(sortedDates.toArray()) // or console.log([...sortedDates]) <script src="https://cdn.jsdelivr.net/npm/blinq#2.0.2"></script>
I have just published to npm a micro-library called sort-helper (source on github). The idea is to import the helper by to create the comparison function for sort array method through the syntax items.sort(by(column, ...otherColumns)), with several way to express the columns to sort by: By key: persons.sort(by('lastName', 'firstName')), By selector: dates.sort(by(x => x.toISOString())), In descending order: [3, 2, 4, 1].sort(by(desc(n => n))) β [3, 2, 1, 0], Ignoring case: ['B', 'D', 'c', 'a'].sort(by(ignoreCase(x => x))).join('') β 'aBcD'. It's similar to the nice thenBy mentioned in this answer but with the following differences that may be more to the taste of some: An approach more functional than object-oriented (see thenBy fluent API), A syntax a bit terser and still as much readable, natural almost like SQL. Fully implemented in TypeScript, to benefit from type safety and type expressivity.
Sourced from GitHub function sortMethodAsc(a, b) { return a == b ? 0 : a > b ? 1 : -1; } function sortMethodWithDirection(direction) { if (direction === undefined || direction == "asc") { return sortMethodAsc; } else { return function(a, b) { return -sortMethodAsc(a, b); } } } function sortMethodWithDirectionByColumn(columnName, direction){ const sortMethod = sortMethodWithDirection(direction) return function(a, b){ return sortMethod(a[columnName], b[columnName]); } } function sortMethodWithDirectionMultiColumn(sortArray) { //sample of sortArray // sortArray = [ // { column: "column5", direction: "asc" }, // { column: "column3", direction: "desc" } // ] const sortMethodsForColumn = (sortArray || []).map( item => sortMethodWithDirectionByColumn(item.column, item.direction) ); return function(a,b) { let sorted = 0; let index = 0; while (sorted === 0 && index < sortMethodsForColumn.length) { sorted = sortMethodsForColumn[index++](a,b); } return sorted; } } //============================================= //============================================= //============================================= //test var data = [ {"CountryName":"Aruba","CountryCode":"ABW","GNI":280},{ "CountryName":"Afghanistan","CountryCode":"ABW","GNI":280},{"CountryName":"Angola","CountryCode":"AGO","GNI":280},{"CountryName":"Albania","CountryCode":"ALB","GNI":4320}, {"CountryName":"Arab World","CountryCode":"ARB","GNI":280},{"CountryName":"United Arab Emirates","CountryCode":"ARE","GNI":39130}, {"CountryName":"Argentina","CountryCode":"ARG","GNI":13030},{"CountryName":"Armenia","CountryCode":"ARM","GNI":3990},{"CountryName":"American Samoa","CountryCode":"ASM","GNI":280}, {"CountryName":"Antigua and Barbuda","CountryCode":"ATG","GNI":13810},{"CountryName":"Australia","CountryCode":"AUS","GNI":51360}, {"CountryName":"Austria","CountryCode":"AUT","GNI":45440},{"CountryName":"Azerbaijan","CountryCode":"AZE","GNI":4080},{"CountryName":"Burundi","CountryCode":"BDI","GNI":280}, {"CountryName":"Belgium","CountryCode":"BEL","GNI":41790},{"CountryName":"Benin","CountryCode":"BEN","GNI":800},{"CountryName":"Burkina Faso","CountryCode":"BFA","GNI":590}, {"CountryName":"Bangladesh","CountryCode":"BGD","GNI":1470},{"CountryName":"Bulgaria","CountryCode":"BGR","GNI":7860},{"CountryName":"Bahrain","CountryCode":"BHR","GNI":21150}, {"CountryName":"Bosnia and Herzegovina","CountryCode":"BIH","GNI":4910},{"CountryName":"Belarus","CountryCode":"BLR","GNI":5280}, {"CountryName":"Belize","CountryCode":"BLZ","GNI":4390},{"CountryName":"Bolivia","CountryCode":"BOL","GNI":3130},{"CountryName":"Brazil","CountryCode":"BRA","GNI":8600}, {"CountryName":"Barbados","CountryCode":"BRB","GNI":15270},{"CountryName":"Brunei Darussalam","CountryCode":"BRN","GNI":29600}, {"CountryName":"Bhutan","CountryCode":"BTN","GNI":2660},{"CountryName":"Botswana","CountryCode":"BWA","GNI":6730}, {"CountryName":"Central African Republic","CountryCode":"CAF","GNI":390},{"CountryName":"Canada","CountryCode":"CAN","GNI":42870}, {"CountryName":"Central Europe and the Baltics","CountryCode":"CEB","GNI":13009},{"CountryName":"Switzerland","CountryCode":"CHE","GNI":80560}, {"CountryName":"Chile","CountryCode":"CHL","GNI":13610},{"CountryName":"China","CountryCode":"CHN","GNI":8690},{"CountryName":"Cote d'Ivoire","CountryCode":"CIV","GNI":1580}, {"CountryName":"Cameroon","CountryCode":"CMR","GNI":1370},{"CountryName":"Colombia","CountryCode":"COL","GNI":5890},{"CountryName":"Comoros","CountryCode":"COM","GNI":1280}, {"CountryName":"Cabo Verde","CountryCode":"CPV","GNI":3030},{"CountryName":"Costa Rica","CountryCode":"CRI","GNI":11120}, {"CountryName":"Caribbean small states","CountryCode":"CSS","GNI":8909},{"CountryName":"Cyprus","CountryCode":"CYP","GNI":23720}, {"CountryName":"Czech Republic","CountryCode":"CZE","GNI":18160},{"CountryName":"Germany","CountryCode":"DEU","GNI":43490}, {"CountryName":"Djibouti","CountryCode":"DJI","GNI":1880},{"CountryName":"Dominica","CountryCode":"DMA","GNI":6590},{"CountryName":"Denmark","CountryCode":"DNK","GNI":55220}, {"CountryName":"Dominican Republic","CountryCode":"DOM","GNI":6630},{"CountryName":"Algeria","CountryCode":"DZA","GNI":3940}, {"CountryName":"East Asia & Pacific (excluding high income)","CountryCode":"EAP","GNI":6987},{"CountryName":"Early-demographic dividend","CountryCode":"EAR","GNI":3352}, {"CountryName":"East Asia & Pacific","CountryCode":"EAS","GNI":10171},{"CountryName":"Europe & Central Asia (excluding high income)","CountryCode":"ECA","GNI":7375}, {"CountryName":"Europe & Central Asia","CountryCode":"ECS","GNI":22656},{"CountryName":"Ecuador","CountryCode":"ECU","GNI":5920}, {"CountryName":"Euro area","CountryCode":"EMU","GNI":35645},{"CountryName":"Spain","CountryCode":"ESP","GNI":27180},{"CountryName":"Estonia","CountryCode":"EST","GNI":18190}, {"CountryName":"Ethiopia","CountryCode":"ETH","GNI":740},{"CountryName":"European Union","CountryCode":"EUU","GNI":32784}, {"CountryName":"Fragile and conflict affected situations","CountryCode":"FCS","GNI":1510},{"CountryName":"Finland","CountryCode":"FIN","GNI":44580}, {"CountryName":"Fiji","CountryCode":"FJI","GNI":4970},{"CountryName":"France","CountryCode":"FRA","GNI":37970},{"CountryName":"Gabon","CountryCode":"GAB","GNI":6650}, {"CountryName":"United Kingdom","CountryCode":"GBR","GNI":40530},{"CountryName":"Georgia","CountryCode":"GEO","GNI":3780},{"CountryName":"Ghana","CountryCode":"GHA","GNI":1880}, {"CountryName":"Guinea","CountryCode":"GIN","GNI":790},{"CountryName":"Guinea-Bissau","CountryCode":"GNB","GNI":660}, {"CountryName":"Equatorial Guinea","CountryCode":"GNQ","GNI":7050},{"CountryName":"Greece","CountryCode":"GRC","GNI":18090}, {"CountryName":"Grenada","CountryCode":"GRD","GNI":9180},{"CountryName":"Guatemala","CountryCode":"GTM","GNI":4060},{"CountryName":"Guyana","CountryCode":"GUY","GNI":4500}, {"CountryName":"High income","CountryCode":"HIC","GNI":40142},{"CountryName":"Honduras","CountryCode":"HND","GNI":2250},{"CountryName":"Heavily indebted poor countries (HIPC)","CountryCode":"HPC","GNI":904},{"CountryName":"Croatia","CountryCode":"HRV","GNI":12570},{"CountryName":"Haiti","CountryCode":"HTI","GNI":760},{"CountryName":"Hungary","CountryCode":"HUN","GNI":12870},{"CountryName":"IBRD only","CountryCode":"IBD","GNI":5745},{"CountryName":"IDA & IBRD total","CountryCode":"IBT","GNI":4620},{"CountryName":"IDA total","CountryCode":"IDA","GNI":1313},{"CountryName":"IDA blend","CountryCode":"IDB","GNI":1791}, {"CountryName":"Indonesia","CountryCode":"IDN","GNI":3540},{"CountryName":"IDA only","CountryCode":"IDX","GNI":1074},{"CountryName":"India","CountryCode":"IND","GNI":1800},{"CountryName":"Ireland","CountryCode":"IRL","GNI":55290},{"CountryName":"Iraq","CountryCode":"IRQ","GNI":4630},{"CountryName":"Iceland","CountryCode":"ISL","GNI":60830},{"CountryName":"Israel","CountryCode":"ISR","GNI":37270},{"CountryName":"Italy","CountryCode":"ITA","GNI":31020},{"CountryName":"Jamaica","CountryCode":"JAM","GNI":4760},{"CountryName":"Jordan","CountryCode":"JOR","GNI":3980},{"CountryName":"Japan","CountryCode":"JPN","GNI":38550},{"CountryName":"Kazakhstan","CountryCode":"KAZ","GNI":7970},{"CountryName":"Kenya","CountryCode":"KEN","GNI":1460},{"CountryName":"Kyrgyz Republic","CountryCode":"KGZ","GNI":1130}, {"CountryName":"Cambodia","CountryCode":"KHM","GNI":1230},{"CountryName":"Kiribati","CountryCode":"KIR","GNI":3010},{"CountryName":"St. Kitts and Nevis","CountryCode":"KNA","GNI":16240},{"CountryName":"Kuwait","CountryCode":"KWT","GNI":31430},{"CountryName":"Latin America & Caribbean (excluding high income)","CountryCode":"LAC","GNI":7470},{"CountryName":"Lao PDR","CountryCode":"LAO","GNI":2270},{"CountryName":"Lebanon","CountryCode":"LBN","GNI":8400},{"CountryName":"Liberia","CountryCode":"LBR","GNI":620},{"CountryName":"Libya","CountryCode":"LBY","GNI":5500},{"CountryName":"St. Lucia","CountryCode":"LCA","GNI":8830},{"CountryName":"Latin America & Caribbean","CountryCode":"LCN","GNI":8251},{"CountryName":"Least developed countries: UN classification","CountryCode":"LDC","GNI":1011},{"CountryName":"Low income","CountryCode":"LIC","GNI":774},{"CountryName":"Sri Lanka","CountryCode":"LKA","GNI":3850},{"CountryName":"Lower middle income","CountryCode":"LMC","GNI":2118},{"CountryName":"Low & middle income","CountryCode":"LMY","GNI":4455},{"CountryName":"Lesotho","CountryCode":"LSO","GNI":1210},{"CountryName":"Late-demographic dividend","CountryCode":"LTE","GNI":8518},{"CountryName":"Lithuania","CountryCode":"LTU","GNI":15200},{"CountryName":"Luxembourg","CountryCode":"LUX","GNI":70260},{"CountryName":"Latvia","CountryCode":"LVA","GNI":14740},{"CountryName":"Morocco","CountryCode":"MAR","GNI":2860},{"CountryName":"Moldova","CountryCode":"MDA","GNI":2200},{"CountryName":"Madagascar","CountryCode":"MDG","GNI":400},{"CountryName":"Maldives","CountryCode":"MDV","GNI":9760}, {"CountryName":"Middle East & North Africa","CountryCode":"MEA","GNI":7236},{"CountryName":"Mexico","CountryCode":"MEX","GNI":8610},{"CountryName":"Marshall Islands","CountryCode":"MHL","GNI":4840},{"CountryName":"Middle income","CountryCode":"MIC","GNI":4942},{"CountryName":"Mali","CountryCode":"MLI","GNI":770}, {"CountryName":"Malta","CountryCode":"MLT","GNI":24080},{"CountryName":"Myanmar","CountryCode":"MMR","GNI":1210},{"CountryName":"Middle East & North Africa (excluding high income)","CountryCode":"MNA","GNI":3832},{"CountryName":"Montenegro","CountryCode":"MNE","GNI":7400},{"CountryName":"Mongolia","CountryCode":"MNG","GNI":3270},{"CountryName":"Mozambique","CountryCode":"MOZ","GNI":420},{"CountryName":"Mauritania","CountryCode":"MRT","GNI":1100},{"CountryName":"Mauritius","CountryCode":"MUS","GNI":10130},{"CountryName":"Malawi","CountryCode":"MWI","GNI":320},{"CountryName":"Malaysia","CountryCode":"MYS","GNI":9650},{"CountryName":"North America","CountryCode":"NAC","GNI":56721},{"CountryName":"Namibia","CountryCode":"NAM","GNI":4570},{"CountryName":"Niger","CountryCode":"NER","GNI":360},{"CountryName":"Nigeria","CountryCode":"NGA","GNI":2100}, {"CountryName":"Nicaragua","CountryCode":"NIC","GNI":2130},{"CountryName":"Netherlands","CountryCode":"NLD","GNI":46180},{"CountryName":"Norway","CountryCode":"NOR","GNI":75990},{"CountryName":"Nepal","CountryCode":"NPL","GNI":800},{"CountryName":"Nauru","CountryCode":"NRU","GNI":10220},{"CountryName":"New Zealand","CountryCode":"NZL","GNI":38970},{"CountryName":"OECD members","CountryCode":"OED","GNI":37273},{"CountryName":"Oman","CountryCode":"OMN","GNI":14440},{"CountryName":"Other small states","CountryCode":"OSS","GNI":12199},{"CountryName":"Pakistan","CountryCode":"PAK","GNI":1580},{"CountryName":"Panama","CountryCode":"PAN","GNI":13280},{"CountryName":"Peru","CountryCode":"PER","GNI":5960},{"CountryName":"Philippines","CountryCode":"PHL","GNI":3660},{"CountryName":"Palau","CountryCode":"PLW","GNI":12700},{"CountryName":"Papua New Guinea","CountryCode":"PNG","GNI":2340},{"CountryName":"Poland","CountryCode":"POL","GNI":12730},{"CountryName":"Pre-demographic dividend","CountryCode":"PRE","GNI":1379},{"CountryName":"Portugal","CountryCode":"PRT","GNI":19820},{"CountryName":"Paraguay","CountryCode":"PRY","GNI":5470},{"CountryName":"West Bank and Gaza","CountryCode":"PSE","GNI":3180},{"CountryName":"Pacific island small states","CountryCode":"PSS","GNI":3793},{"CountryName":"Post-demographic dividend","CountryCode":"PST","GNI":41609},{"CountryName":"Qatar","CountryCode":"QAT","GNI":60510},{"CountryName":"Romania","CountryCode":"ROU","GNI":10000},{"CountryName":"Russian Federation","CountryCode":"RUS","GNI":9230},{"CountryName":"Rwanda","CountryCode":"RWA","GNI":720},{"CountryName":"South Asia","CountryCode":"SAS","GNI":1729},{"CountryName":"Saudi Arabia","CountryCode":"SAU","GNI":20090},{"CountryName":"Sudan","CountryCode":"SDN","GNI":2380},{"CountryName":"Senegal","CountryCode":"SEN","GNI":1240},{"CountryName":"Singapore","CountryCode":"SGP","GNI":54530},{"CountryName":"Solomon Islands","CountryCode":"SLB","GNI":1920},{"CountryName":"Sierra Leone","CountryCode":"SLE","GNI":510},{"CountryName":"El Salvador","CountryCode":"SLV","GNI":3560},{"CountryName":"Serbia","CountryCode":"SRB","GNI":5180},{"CountryName":"Sub-Saharan Africa (excluding high income)","CountryCode":"SSA","GNI":1485},{"CountryName":"Sub-Saharan Africa","CountryCode":"SSF","GNI":1486},{"CountryName":"Small states","CountryCode":"SST","GNI":11099},{"CountryName":"Sao Tome and Principe","CountryCode":"STP","GNI":1770},{"CountryName":"Suriname","CountryCode":"SUR","GNI":5150},{"CountryName":"Slovak Republic","CountryCode":"SVK","GNI":16610},{"CountryName":"Slovenia","CountryCode":"SVN","GNI":22000},{"CountryName":"Sweden","CountryCode":"SWE","GNI":52590},{"CountryName":"Eswatini","CountryCode":"SWZ","GNI":2950},{"CountryName":"Seychelles","CountryCode":"SYC","GNI":14170},{"CountryName":"Chad","CountryCode":"TCD","GNI":640},{"CountryName":"East Asia & Pacific (IDA & IBRD countries)","CountryCode":"TEA","GNI":7061}, {"CountryName":"Europe & Central Asia (IDA & IBRD countries)","CountryCode":"TEC","GNI":7866},{"CountryName":"Togo","CountryCode":"TGO","GNI":610},{"CountryName":"Thailand","CountryCode":"THA","GNI":5950},{"CountryName":"Tajikistan","CountryCode":"TJK","GNI":990},{"CountryName":"Turkmenistan","CountryCode":"TKM","GNI":6380},{"CountryName":"Latin America & the Caribbean (IDA & IBRD countries)","CountryCode":"TLA","GNI":8179},{"CountryName":"Timor-Leste","CountryCode":"TLS","GNI":1790},{"CountryName":"Middle East & North Africa (IDA & IBRD countries)","CountryCode":"TMN","GNI":3839},{"CountryName":"Tonga","CountryCode":"TON","GNI":4010},{"CountryName":"South Asia (IDA & IBRD)","CountryCode":"TSA","GNI":1729}, {"CountryName":"Sub-Saharan Africa (IDA & IBRD countries)","CountryCode":"TSS","GNI":1486},{"CountryName":"Trinidad and Tobago","CountryCode":"TTO","GNI":15340},{"CountryName":"Tunisia","CountryCode":"TUN","GNI":3490},{"CountryName":"Turkey","CountryCode":"TUR","GNI":10940},{"CountryName":"Tuvalu","CountryCode":"TUV","GNI":4970},{"CountryName":"Tanzania","CountryCode":"TZA","GNI":910},{"CountryName":"Uganda","CountryCode":"UGA","GNI":600},{"CountryName":"Ukraine","CountryCode":"UKR","GNI":2390},{"CountryName":"Upper middle income","CountryCode":"UMC","GNI":8197},{"CountryName":"Uruguay","CountryCode":"URY","GNI":15250},{"CountryName":"United States","CountryCode":"USA","GNI":58270},{"CountryName":"Uzbekistan","CountryCode":"UZB","GNI":2000},{"CountryName":"St. Vincent and the Grenadines","CountryCode":"VCT","GNI":7390},{"CountryName":"Vietnam","CountryCode":"VNM","GNI":2160},{"CountryName":"Vanuatu","CountryCode":"VUT","GNI":2920},{"CountryName":"World","CountryCode":"WLD","GNI":10371},{"CountryName":"Samoa","CountryCode":"WSM","GNI":4090},{"CountryName":"Kosovo","CountryCode":"XKX","GNI":3900}, {"CountryName":"South Africa","CountryCode":"ZAF","GNI":5430},{"CountryName":"Zambia","CountryCode":"ZMB","GNI":1290},{"CountryName":"Zimbabwe","CountryCode":"ZWE","GNI":1170}, {"CountryName":"Zimbabwe","CountryCode":"ZWE","GNI":1171}]; const sortMethod = sortMethodWithDirectionMultiColumn( [ { column: "GNI", direction: "asc" }, { column: "CountryCode", direction: "desc" } ] ); let sortedData = data.sort(sortMethod); console.log("sorted by: 1)column:GNI-asc, 2)column:CountryCode-desc") console.table(sortedData); console.log(sortedData);
I need this for a small project I'm working on, so performance is not a priority. I have two arrays, main array I want to be sorted, and array of sorting rules. I loop that rules array inside sorting callback function, and try to exit that loop as soon as possible. I use multiplier in order to convert -1 to 1 depending on weather I'm sorting a property in ascending or descending order. let array = [ {fullName: 'Michael Schumacher', sport: 'Formula 1'}, {fullName: 'Michael Jordan', sport: 'Basketball'}, {fullName: 'Damon Hill', sport: 'Formula 1'}, {fullName: 'Kobe Bryant', sport: 'Basketball'}, {fullName: 'Lebron James', sport: 'Basketball'}, {fullName: 'Lewis Hamilton', sport: 'Formula 1'}, ]; const sortArray = (array, options) => { if (!Array.isArray(options)) { options = [{ key: options, order: 'asc' }]; } options.forEach(item => { item.multiplier = item.order != 'desc' ? -1 : 1; }); return array.sort((firstItem, secondItem) => { for (item of options) { const { key, multiplier } = item; const firstValue = firstItem[key]; const secondValue = secondItem[key]; if (firstValue != secondValue) { return multiplier * (firstValue < secondValue ? 1 : -1); } } return 0; }); } console.log('Original array'); console.log([...array]); sortArray(array, 'sport'); console.log('Sorted by sport only (ascending, implicit, keeping the same order of athletes)'); console.log([...array]); sortArray(array, [{key: 'sport'}, {key: 'fullName', order: 'desc'}]); console.log('Sorted by sport (ascending, implicit), and by fullName (descending)'); console.log(array);
To simplify the understanding The sort method compares numbers, if below 0, it sorts it to the let, if above zero it sorts it to the right. So to add multi level sorting, check if the match === 0, then further sort it. See example below ['a/b/c', 'a long piece of text/b', 'apple/b'].sort((a, b) => { const asc = a.split('/').length - b.split('/').length return asc }) // outputs ['a long piece of text/b', 'apple/b', 'a/b/c'] ['a/b/c', 'a long piece of text/b', 'apple/b'].sort((a, b) => { const asc = a.split('/').length - b.split('/').length return asc === 0 ? a.length - b.length : asc }) // outputs: 'apple/b', 'a long piece of text/b', 'a/b/c'
I see a lot of complicated solutions, so I'll paste here what I'm using: assignedIssues.sort((a, b) => { let order = sortByText(a.assignee?.username, b.assignee?.username) if (order === 0) order = sort(a.labels, b.labels, statusLabels) if (order === 0) order = sort(a.labels, b.labels, priorityLabels) if (order === 0) order = sortByText(a.web_url, b.web_url) return order }) I think that this is much more readable, let you implement any custom sorting function for each level, without calling all unnecessarily.
Assuming you want to sort by multiple indexes, and assuming that you don't know the type of each field (string, number, or null). You can create a function to sort with as many indexes as you like. const compareWithType = (a, b) => { if (typeof a === 'string') return a.localeCompare(b); if (typeof a === 'number') return a - b; return (!!a) - (!!b); // to sort non-string non-number falsy or null values, modify as you like. } const compareWithIndexes = (...indexes) => { return (a, b) => { for (let i in indexes) { let diff = 0; while (!diff) { compareWithType(a[i], b[i]); } return diff; } } } [[1, 2, 3, 4, 5], [0, 2, 3, 4, 6]].sort(compareWithIndexes(2, 3, 4)); // compares (3 - 3) then (4 - 4) then (5 - 6)
Despite a lot of complicated answers here, I still like the basic way to do it var arr = [ [3, 'pub2', 1, 'ownA'], [1, 'pub1', 2, 'ownA'], [2, 'pub1', 3, 'ownC'] ]; // sorting priority is bottom to top, in this case owner name then publication name // sort publication name arr.sort((a,b) => a[1].localeCompare(b[1])); // sort owner name arr.sort((a,b) => a[3].localeCompare(b[3])); console.log(arr);
Sort Array Object with Multiple Keys: Javascript
Well, I have an array objects with random values, Ex. var arr = [ { id:1001, date:"20-02-2014", Name: 'demo1' }, { id:1004, date:"13-02-2014", Name: 'demo0' }, { id:1000, date:"10-02-2014", Name: 'demo14' }, { id:1004, date:"16-02-2014", Name: 'demo10' }, { id:1006, date:"22-02-2014", Name: 'demo111' }, { id:1003, date:"28-02-2014", Name: 'demo16' }, { id:1000, date:"28-01-2014", Name: 'demo12' }, { id:1004, date:"28-01-2014", Name: 'demo01' }, { id:1000, date:"08-01-2014", Name: 'demo41' }, { id:1006, date:"08-01-2014", Name: 'demo91' } ] I wanted to sort this array firstly by key id & then by key date as, Output: sorted_arr = [ {"id":1000,"date":"08-01-2014","Name":"demo41"}, //group1 {"id":1000,"date":"28-01-2014","Name":"demo12"}, //group1 {"id":1000,"date":"10-02-2014","Name":"demo14"}, //group1 {"id":1001,"date":"20-02-2014","Name":"demo1"}, //group2 {"id":1003,"date":"28-02-2014","Name":"demo16"}, //group3 {"id":1004,"date":"28-01-2014","Name":"demo01"}, //group4 {"id":1004,"date":"13-02-2014","Name":"demo0"}, //group4 {"id":1004,"date":"16-02-2014","Name":"demo10"}, //group4 {"id":1006,"date":"08-01-2014","Name":"demo91"} //group5 {"id":1006,"date":"22-02-2014","Name":"demo111"} //group5 ] I tried few generic code to sort, // generic comparison function cmp = function(x, y){ return x > y ? 1 : x < y ? -1 : 0; }; arr.sort(function(a, b){ return cmp( [cmp(a.id, b.id), cmp(a.date, b.date)], [cmp(b.id, a.id), cmp(b.date, a.date)] ); }); I referred few examples SO Example but not getting expected output. Please suggest me best way to get this.
No need to create Date objects, just reorder the date string into a sortable string, example This example assumes that your dates are in the same format DD-MM-YYYY and creates YYYYMMDD for the date sort. Javascript var arr = [ { id:1001, date:"20-02-2014", Name: 'demo1' }, { id:1004, date:"13-02-2014", Name: 'demo0' }, { id:1000, date:"10-02-2014", Name: 'demo14' }, { id:1004, date:"16-02-2014", Name: 'demo10' }, { id:1006, date:"22-02-2014", Name: 'demo111' }, { id:1003, date:"28-02-2014", Name: 'demo16' }, { id:1000, date:"28-01-2014", Name: 'demo12' }, { id:1004, date:"28-01-2014", Name: 'demo01' }, { id:1000, date:"08-01-2014", Name: 'demo41' }, { id:1006, date:"08-01-2014", Name: 'demo91' } ]; var sorted = arr.sort(function (a, b) { return a.id - b.id || a.date.split('-').reverse().join('') - b.date.split('-').reverse().join(''); }); sorted.forEach(function (element) { console.log(JSON.stringify(element)); }); Output {"id":1000,"date":"08-01-2014","Name":"demo41"} {"id":1000,"date":"28-01-2014","Name":"demo12"} {"id":1000,"date":"10-02-2014","Name":"demo14"} {"id":1001,"date":"20-02-2014","Name":"demo1"} {"id":1003,"date":"28-02-2014","Name":"demo16"} {"id":1004,"date":"28-01-2014","Name":"demo01"} {"id":1004,"date":"13-02-2014","Name":"demo0"} {"id":1004,"date":"16-02-2014","Name":"demo10"} {"id":1006,"date":"08-01-2014","Name":"demo91"} {"id":1006,"date":"22-02-2014","Name":"demo111"} On jsFiddle If there is any concern over mixing date formats, as discussed with #xdazz, then you can improve on this by checking the padding yourself. The following creates the format 'YYYYYYMMDD' when sorting by the date. The extra year padding is not necessary in this example as I am taking the numeric difference of the values, but if you choose to compare the strings then it is important. function pad(s, n) { var v = '', i; for(i = 0; i < n - s.length; i += 1) { v += '0'; } return v + s; } var sorted = arr.sort(function (a, b) { var idDiff = a.id - b.id; if (idDiff) { return idDiff; } var ordA = a.date.split('-').reverse(), ordB = b.date.split('-').reverse(); ordA[0] = pad(ordA[0], 6); ordA[1] = pad(ordA[1], 2); ordA[2] = pad(ordA[2], 2); ordA = ordA.join(''); ordB[0] = pad(ordB[0], 6); ordB[1] = pad(ordB[1], 2); ordB[2] = pad(ordB[2], 2); ordB = ordB.join(''); return ordA - ordB; }); On jsFiddle If you really want to use Date objects the I would suggest the following. var sorted = arr.sort(function (a, b) { var idDiff = a.id - b.id; if (idDiff) { return idDiff; } var ordA = a.date.split('-').reverse(), ordB = b.date.split('-').reverse(); ordA[1] -= 1; ordB[1] -= 1; return new Date(Date.UTC.apply(undefined, ordA)).valueOf() - new Date(Date.UTC.apply(undefined, ordB)).valueOf(); }); sorted.forEach(function (element) { console.log(JSON.stringify(element)); }); On jsFiddle Note: These examples do not handle dates with negative years, again you would need to make further modifications.
First compare with id, then compare with date if id equal. But because your date is in invalid date format, extra work has to be done for letting it be recognized by Date. sorted_arr = arr.sort(function(a, b) { return a.id - b.id || new Date(a.date.split('-').reverse().join('-')) - new Date(b.date.split('-').reverse().join('-')); }); Edit: If you are guaranteed to have zeros in front of the 1-digit months and dates, then you could even not to parse to date: sorted_arr = arr.sort(function(a, b) { return a.id - b.id || a.date.split('-').reverse().join('') - b.date.split('-').reverse().join(''); });
It's better to have a date operate lib momentjs to help. You could check the code on jsBin function compare(a, b){ var idDiff = a.id - b.id; var adate = moment(a.date, "DD-MM-YYYY"); var bdate = moment(b.date, "DD-MM-YYYY"); var dateDiff = adate.diff(bdate); return idDiff || dateDiff; } var sortedArr = arr.sort(compare); console.log(sortedArr);
You can sort array by two properties with Alasql library: var res = alasql('SELECT *, mid(date,7,4)+mid(date,4,2)+mid(date,1,2) AS ndate \ FROM ? ORDER BY id, ndate',[arr]); Try this example at jsFiddle. Here "mid(date,7,4)+mid(date,4,2)+mid(date,1,2)" was used to convert date from '28-11-2014' to the sort key like '20141128'.
Came up with this using underscore.js & it's chain and sortBy: var sorted_array = _(arr).chain().sortBy(function(o) { return o.date.split('-').reverse().join(); }).sortBy(function(o) { return o.id; }).value(); Sorting on the date first, and then id will give you the list sorted as expected. jsfiddle
How to sort an object array by date property?
Say I have an array of a few objects: var array = [{id: 1, date: Mar 12 2012 10:00:00 AM}, {id: 2, date: Mar 8 2012 08:00:00 AM}]; How can I sort this array by the date element in order from the date closest to the current date and time down? Keep in mind that the array may have many objects, but for the sake of simplicity I used 2. Would I use the sort function and a custom comparator?
Simplest Answer 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); }); More Generic Answer array.sort(function(o1,o2){ if (sort_o1_before_o2) return -1; else if(sort_o1_after_o2) return 1; else return 0; }); Or more tersely: array.sort(function(o1,o2){ return sort_o1_before_o2 ? -1 : sort_o1_after_o2 ? 1 : 0; }); Generic, Powerful Answer Define a custom non-enumerable sortBy function using a Schwartzian transform on all arrays : (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 it like so: array.sortBy(function(o){ return o.date }); If your date is not directly comparable, make a comparable date out of it, e.g. array.sortBy(function(o){ return new Date( o.date ) }); You can also use this to sort by multiple criteria if you return an array of values: // Sort by date, then score (reversed), then name array.sortBy(function(o){ return [ o.date, -o.score, o.name ] }; See http://phrogz.net/JS/Array.prototype.sortBy.js for more details.
#Phrogz answers are both great, but here is a great, more concise answer: array.sort(function(a,b){return a.getTime() - b.getTime()}); Using the arrow function way array.sort((a,b)=>a.getTime()-b.getTime()); found here: Sort date in Javascript
After correcting the JSON this should work for you now: 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; });
Your data needs some corrections: var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}]; After correcting the data, you can use this piece of code: 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);β
Above answers are all good π, here is my implementation of sorting date in ES6 way, I'm using Date.parse (is global Date object) this will convert string representation of Date to number of milliseconds. Instead of instantiating new Date object every time. var array = ["2021-08-10T07:24:30.087+0000" , "2021-09-30T07:24:30.087+0000", "2021-10-13T07:24:30.087+0000"]; // sorting with latest date array.sort((a,b) => Date.parse(b) - Date.parse(a))
I recommend GitHub: Array sortBy - a best implementation of sortBy method which uses the Schwartzian transform But for now we are going to try this approach Gist: sortBy-old.js. Let's create a method to sort arrays being able to arrange objects by some property. Creating the sorting function 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)); }); }; }()); Setting unsorted data 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"} ]; Using it Finally, we arrange the array, by "date" property as string //sort the object by a property (ascending) //sorting takes into account uppercase and lowercase sortBy(data, { prop: "date" }); If you want to ignore letter case, set the "parser" callback: //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(); } }); If you want to treat the "date" field as Date type: //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); } }); Here you can play with the above example: jsbin.com/lesebi
This should do when your date is in this format (dd/mm/yyyy). sortByDate(arr) { arr.sort(function(a,b){ return Number(new Date(a.readableDate)) - Number(new Date(b.readableDate)); }); return arr; } Then call sortByDate(myArr);
arr is an array of object and each object has date_prop which is a date. You can sort it in descending/decreasing order like this arr = arr.sort(function (a, b) { var dateA = new Date(a.date_prop).getTime(); var dateB = new Date(b.date_prop).getTime(); return dateA < dateB ? 1 : -1; // ? -1 : 1 for ascending/increasing order });
You could use sortBy in underscore js. http://underscorejs.org/#sortBy Sample: 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'));
With ES6 arrow functions, you can further write just one line of concise code (excluding variable declaration). Eg.: var isDescending = true; //set to false for ascending console.log(["8/2/2020","8/1/2020","8/13/2020", "8/2/2020"].sort((a,b) => isDescending ? new Date(b).getTime() - new Date(a).getTime() : new Date(a).getTime() - new Date(b).getTime())); Since time does not exists with the above dates, the Date object will consider following default time for sorting: 00:00:00 The code will work for both ascending and descending sort. Just change the value of isDescending variable as required.
Strings with dates are comparable in JavaScript (if they are syntactically the same), e.g.: '2020-12-01' < '2020-12-02' == true This means you can use this expression in a custom sort function: var arr = [{id:1, date:'2020-12-01'}, {id:1, date:'2020-12-15'}, {id:1, date:'2020-12-12'}] function sortByDate(a, b) { if (a.date < b.date) { return 1; } if (a.date > b.date) { return -1; } return 0; } const sorted = arr.sort(sortByDate); console.log(sorted);
I'm going to add this here, as some uses may not be able to work out how to invert this sorting method. To sort by 'coming up', we can simply swap a & b, like so: your_array.sort ( (a, b) => { return new Date(a.DateTime) - new Date(b.DateTime); }); Notice that a is now on the left hand side, and b is on the right, :D!
i was able to achieve sorting using below lines: array.sort(function(a, b) { if (a.DueDate > b.DueDate) return 1; if (a.DueDate < b.DueDate) return -1; })
I personally use following approach to sort dates. 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; })
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)) });
Here is the shortest way to solve your problem. var array = [{id: 1, date: 'Mar 12 2012 10:00:00 AM'}, {id: 2, date: 'Mar 8 2012 08:00:00 AM'}]; var sortedArray = array.sort((a,b) => Date.parse(new Date(a.date)) - Date.parse(new Date(b.date)));
Simple one line solution for me to sort dates : sort((a, b) => (a < b ? 1 : -1))
Thank you Ganesh Sanap. sorting items by date field from old to new. Use it 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; });
["12 Jan 2018" , "1 Dec 2018", "04 May 2018"].sort(function(a,b) { return new Date(a).getTime() - new Date(b).getTime() })
For anyone who is wanting to sort by date (UK format), I used the following: //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; }); }
I have just taken the Schwartzian transform depicted above and made as function. It takes an array, the sorting function and a boolean as input: 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));
If like me you have an array with dates formatted like YYYY[-MM[-DD]] where you'd like to order more specific dates before less specific ones, I came up with this handy function: 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) }
Thanks for those brilliant answers on top. I have thought a slightly complicated answer. Just for those who want to compare different answers. const data = [ '2-2018', '1-2018', '3-2018', '4-2018', '1-2019', '2-2019', '3-2019', '4-2019', '1-2020', '3-2020', '4-2020', '1-2021' ] let eachYearUniqueMonth = data.reduce((acc, elem) => { const uniqueDate = Number(elem.match(/(\d+)\-(\d+)/)[1]) const uniqueYear = Number(elem.match(/(\d+)\-(\d+)/)[2]) if (acc[uniqueYear] === undefined) { acc[uniqueYear] = [] } else{ if (acc[uniqueYear] && !acc[uniqueYear].includes(uniqueDate)) { acc[uniqueYear].push(uniqueDate) } } return acc; }, {}) let group = Object.keys(eachYearUniqueMonth).reduce((acc,uniqueYear)=>{ eachYearUniqueMonth[uniqueYear].forEach(uniqueMonth=>{ acc.push(`${uniqueYear}-${uniqueMonth}`) }) return acc; },[]) console.log(group); //["2018-1", "2018-3", "2018-4", "2019-2", "2019-3", "2019-4", "2020-3", "2020-4"]
I have an array of objects in which key 'time' contains the date in ISO format Example - 2021-12-24T11:02:20.370705 arr.sort(function(a,b){return a.time > b.time ? 1 : a.time < b.time ? -1 : 0 }); Above worked for me like a charm!
If you are into MongoDB, one of the solutions is: db.collection.find({}).sort("your date field"); For example: db.collection.find({}).sort("createdAt");
Sorting an Array of Objects by two Properties
I've got an Array of Objects I want to sort by two Properties: RemindingTimestamp ModificationTimestamp Sorting order: 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 (e.g. ISO8601 and same time zone), try: 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. Dates that don't sort because they don't subtract (e.g. 2012-04-12) can be handled by conversion to dates first, e.g. // 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).
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 Resources: MDN: Array.sort()
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). 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 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. If both RemindingTimestamp and ModificationTimestamp are numbers, you could alternatively do: myArray.sortBy(function(obj){ return [-obj.RemindingTimestamp, -obj.ModificationTimestamp]; }); Here is the code that adds sortBy to arrays: (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); 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: 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)); }