I have an array of objects with several key value pairs, and I need to sort them based on \'updated_at\':
[
{
\"updated_at\" : \"2012-01-01T06:25
I have created a sorting function in Typescript which we can use to search strings, dates and numbers in array of objects. It can also sort on multiple fields.
export type SortType = 'string' | 'number' | 'date';
export type SortingOrder = 'asc' | 'desc';
export interface SortOptions {
sortByKey: string;
sortType?: SortType;
sortingOrder?: SortingOrder;
}
class CustomSorting {
static sortArrayOfObjects(fields: SortOptions[] = [{sortByKey: 'value', sortType: 'string', sortingOrder: 'desc'}]) {
return (a, b) => fields
.map((field) => {
if (!a[field.sortByKey] || !b[field.sortByKey]) {
return 0;
}
const direction = field.sortingOrder === 'asc' ? 1 : -1;
let firstValue;
let secondValue;
if (field.sortType === 'string') {
firstValue = a[field.sortByKey].toUpperCase();
secondValue = b[field.sortByKey].toUpperCase();
} else if (field.sortType === 'number') {
firstValue = parseInt(a[field.sortByKey], 10);
secondValue = parseInt(b[field.sortByKey], 10);
} else if (field.sortType === 'date') {
firstValue = new Date(a[field.sortByKey]);
secondValue = new Date(b[field.sortByKey]);
}
return firstValue > secondValue ? direction : firstValue < secondValue ? -(direction) : 0;
})
.reduce((pos, neg) => pos ? pos : neg, 0);
}
}
}
Usage:
const sortOptions = [{
sortByKey: 'anyKey',
sortType: 'string',
sortingOrder: 'asc',
}];
arrayOfObjects.sort(CustomSorting.sortArrayOfObjects(sortOptions));
For completeness here is a possible short generic implementation of sortBy:
function sortBy(list, keyFunc) {
return list.sort((a,b) => keyFunc(a) - keyFunc(b));
}
sortBy([{"key": 2}, {"key": 1}], o => o["key"])
Note that this uses the arrays sort method that sorts in place. for a copy you can use arr.concat() or arr.slice(0) or similar method to create a copy.
The Array.sort() method sorts the elements of an array in place and returns the array. Be careful with Array.sort() as it's not Immutable. For immutable sort use immutable-sort.
This method is to sort the array using your current updated_at
in ISO format. We use new Data(iso_string).getTime()
to convert ISO time to Unix timestamp. A Unix timestamp is a number that we can do simple math on. We subtract the first and second timestamp the result is; if the first timestamp is bigger than the second the return number will be positive. If the second number is bigger than the first the return value will be negative. If the two are the same the return will be zero. This alines perfectly with the required return values for the inline function.
For ES6:
arr.sort((a,b) => new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime());
For ES5:
arr.sort(function(a,b){
return new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime();
});
If you change your updated_at
to be unix timestamps you can do this:
For ES6:
arr.sort((a,b) => a.updated_at - b.updated_at);
For ES5:
arr.sort(function(a,b){
return a.updated_at - b.updated_at;
});
At the time of this post, modern browsers do not support ES6. To use ES6 in modern browsers use babel to transpile the code to ES5. Expect browser support for ES6 in the near future.
Array.sort() should receave a return value of one of 3 possible outcomes:
Note that the return value on the inline function can be any positive or negative number. Array.Sort() does not care what the return number is. It only cares if the return value is positive, negative or zero.
For Immutable sort: (example in ES6)
const sort = require('immutable-sort');
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);
You can also write it this way:
import sort from 'immutable-sort';
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);
The import-from you see is a new way to include javascript in ES6 and makes your code look very clean. My personal favorite.
Immutable sort doesn't mutate the source array rather it returns a new array. Using const
is recommended on immutable data.
var months = [
{
"updated_at" : "2012-01-01T06:25:24Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-09T11:25:13Z",
"foo" : "bar"
},
{
"updated_at" : "2012-01-05T04:13:24Z",
"foo" : "bar"
}];
months.sort((a, b)=>{
var keyA = new Date(a.updated_at),
keyB = new Date(b.updated_at);
// Compare the 2 dates
if(keyA < keyB) return -1;
if(keyA > keyB) return 1;
return 0;
});
console.log(months);
I face with same thing, so i handle this with a generic why and i build a function for this:
//example: //array: [{name: 'idan', workerType: '3'}, {name: 'stas', workerType: '5'}, {name: 'kirill', workerType: '2'}] //keyField: 'workerType' // keysArray: ['4', '3', '2', '5', '6']
sortByArrayOfKeys = (array, keyField, keysArray) => {
array.sort((a, b) => {
const aIndex = keysArray.indexOf(a[keyField])
const bIndex = keysArray.indexOf(b[keyField])
if (aIndex < bIndex) return -1;
if (aIndex > bIndex) return 1;
return 0;
})
}
I already answered a really similar question here: Simple function to sort an array of objects
For that question I created this little function that might do what you want:
function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a[key]; var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}