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));
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 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 ) );
I´m using Angular2 and I have an array with Date-Objects (~1000).
Most of the Date-Objects have got the exactly same dates (for example 2016_11_02; Dates have no hours & minutes).
Normally there should be about ~10-20 different Dates in the Array.
Now i want to filter this array and delete the duplicate Dates.
So in the end there should be about ~10-20 Date-Objects in the array.
Here´s the code i tried:
let uniqueArray = duplicatesArray.filter(function(elem, pos) {
return channelEPGDates.indexOf(elem) == pos;
});
console.log('unique: ' + uniqueArray.length);
I know this is not correct, cause the unique-Array has the same length as the old array. But how can i compare the Dates itself in the filter-function?
Thanks so much!
I would map the dates to epoch time using the getTime method, and then map them back to Date objects.
let uniqueArray = duplicatesArray
.map(function (date) { return date.getTime() })
.filter(function (date, i, array) {
return array.indexOf(date) === i;
})
.map(function (time) { return new Date(time); });
You could use Set and the spread syntax ... for it.
unique = src => [...new Set(src)];
var unique = src => [...new Set(src)];
array = ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Nancy", "Carl"];
console.log(unique(array));
To get objects with unique dates, you could filter the data by using a closure over a Set and a callback for getting the part which has to be unique.
var unique = (src, fn) => src.filter((s => o => !s.has(fn(o)) && s.add(fn(o)))(new Set));
array = [{ date: new Date('2019-11-01')}, { date: new Date('2019-11-01')}, { date: new Date('2019-11-01')}, { date: new Date('2019-11-02')}, { date: new Date('2019-11-01')}, { date: new Date('2019-11-05')}, { date: new Date('2019-11-05')}, { date: new Date('2019-11-04')}, { date: new Date('2019-11-07')}];
console.log(unique(array, ({ date }) => date.toISOString().slice(0, 10)));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do with jQuery like this :
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
Here is a method using the built-in methods on Array.
var arr = ["John", "Jimmy", "John"];
var dArr = []; //Date array
while (dArr.length < 10000) { //Load a lot of pseudo dates
dArr.push(
new Date().getTime() + Math.round(Math.random() * 10)
);
}
function arrayUnique(arr) {
return arr.reduce(function(previousValue, currentValue) {
if (previousValue.some(function(value, index) {
return value === currentValue;
}) === false) {
previousValue.push(currentValue);
}
return previousValue;
}, []);
}
console.log(arrayUnique(arr));
console.log(arrayUnique(dArr).sort());
I am trying to sort an array of objects with each object containing:
var recent = [{id: "123",age :12,start: "10/17/13 13:07"} , {id: "13",age :62,start: "07/30/13 16:30"}];
Date format is: mm/dd/yy hh:mm.
I want to sort in order of date with the most recent first. If date is same it should be sorted by their time parts.
I tried out the below sort() function, but it is not working:
recent.sort(function(a,b))
{
a = new Date(a.start);
b = new Date(b.start);
return a-b;
});
Also how should I iterate over the objects for sorting? Something like:
for (var i = 0; i < recent.length; i++)
{
recent[i].start.sort(function (a, b)
{
a = new Date(a.start);
b = new Date(b.start);
return a-b;
} );
}
There can be any number of objects in the array.
As has been pointed out in the comments, the definition of recent isn't correct javascript.
But assuming the dates are strings:
var recent = [
{id: 123,age :12,start: "10/17/13 13:07"},
{id: 13,age :62,start: "07/30/13 16:30"}
];
then sort like this:
recent.sort(function(a,b) {
return new Date(a.start).getTime() - new Date(b.start).getTime()
});
More details on sort function from W3Schools
recent.sort(function(a,b) { return new Date(a.start).getTime() - new Date(b.start).getTime() } );
ES6:
recent.sort((a,b)=> new Date(b.start).getTime()-new Date(a.start).getTime());
This function allows you to create a comparator that will walk a path to the key you would like to compare on:
function createDateComparator ( path = [] , comparator = (a, b) => a.getTime() - b.getTime()) {
return (a, b) => {
let _a = a
let _b = b
for(let key of path) {
_a = _a[key]
_b = _b[key]
}
return comparator(_a, _b)
}
}
const input = (
[ { foo: new Date(2017, 0, 1) }
, { foo: new Date(2018, 0, 1) }
, { foo: new Date(2016, 0, 1) }
]
)
const result = input.sort(createDateComparator([ 'foo' ]))
console.info(result)