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;
I have two arrays one with all the start date (arrayStart) and the second with all the end date (arrayEnd).
I need to have all dates between the start and the end date. Each value matches on both array (arrayStart[0] matches arrayEnd[0], how can I do that?
Here is my code :
try {
let res = await axios.get(`https://myseenapp.herokuapp.com/constructionSite/${_id}`);
let data = res.data;
setConstruction(data);
setStartDate(
data
.map(e => e.startDate)
.forEach((day) => {
let convert = day.split('-').reverse().join('-')
if (arrayStart.includes(convert) === false) {
arrayStart.push(convert)
}
}));
setEndDate(
data
.map(e => e.endDate)
.forEach((day) => {
let convert = day.split('-').reverse().join('-')
if (arrayEnd.includes(convert) === false) {
arrayEnd.push(convert)
}
})
);
const start = (item) => {
console.log(moment(item).format("YYYY-MM-DD"))
}
arrayStart.forEach(start);
const end = (item) => {
console.log(moment(item).format("YYYY-MM-DD"))
}
arrayEnd.forEach(end);
let s = start(item);
const getDaysBetweenDates = (start, end) => {
let now = start;
let dates = [];
while (now <= end){
dates.push(now.format("YYYY-MM-DD"));
now.add(1, 'days');
dates.forEach((day) => {
newDaysObject[day] = {
textColor: "white",
color: 'gold',
selected: true,
}
})
}
return dates;
}
let dateList = getDaysBetweenDates(start, end);
console.log(dateList)
}
catch (err) {
console.log(err)
}
};
Use getDates() to get an array of dates b/w two dates. code link
Date.prototype.addDays = function(days) {
var dat = new Date(this.valueOf())
dat.setDate(dat.getDate() + days);
return dat;
}
function getDates(startDate, stopDate) {
var dateArray = new Array();
var currentDate = startDate;
while (currentDate <= stopDate) {
dateArray.push(currentDate)
currentDate = currentDate.addDays(1);
}
return dateArray;
}
var dateArray = getDates(new Date(), (new Date()).addDays(10));
Hi I'm having an array of the date object
"["2021-01-05T06:30:00.000Z","2021-01-06T06:30:00.000Z",
"2021-01-20T06:30:00.000Z","2021-02-09T06:30:00.000Z",
"2021-02-23T06:30:00.000Z","2021-02-16T06:30:00.000Z",
"2020-12-08T06:30:00.000Z","2020-12-15T06:30:00.000Z",
"2020-12-02T06:30:00.000Z","2020-12-09T06:30:00.000Z",
"2020-12-16T06:30:00.000Z"]"
I need to format into this
[
{
"month": "12",
"year": "2020",
"dates": [1,14,25]
},
{
"month": "10",
"year": "2020",
"dates": [1]
}
]
How to format like this help me. I have done like this but not completed I was stuck in adding dates. I know this is not the correct way of doing it. Please don't bother the code I have written I know it's garbage.
dateArray.reduce((initial,next)=>{
let result=[]
if(isSameYear(new Date(initial),new Date(next) &&
isSameMonth(new Date(initial),new Date(next))){
result.push({
month:new Date(nex).getMonth(),
year: new Date(next).getFullYear
})
}
})
You can group dates based on year and month in an object accumulator.
const data = ["2021-01-05T06:30:00.000Z", "2021-01-06T06:30:00.000Z", "2021-01-20T06:30:00.000Z", "2021-02-09T06:30:00.000Z", "2021-02-23T06:30:00.000Z", "2021-02-16T06:30:00.000Z", "2020-12-08T06:30:00.000Z", "2020-12-15T06:30:00.000Z", "2020-12-02T06:30:00.000Z", "2020-12-09T06:30:00.000Z", "2020-12-16T06:30:00.000Z" ],
result = Object.values(data.reduce((r, date) => {
const [year, month, day] = date.substr(0,10).split('-');
const key = `${year}_${month}`;
r[key] = r[key] || {month, year, dates: []};
r[key].dates.push(day);
return r;
},{}));
console.log(result);
When you group things in general, it's easier to group them into an object. The reason is you don't have to search an array for a matching result to append to, you only have to look up a key to concatenate to.
Here's one solution that builds an object, grouped by string keys built out of the month and year, and then maps over the values of that object to build the array you're looking for, by splitting the string keys into their significant parts.
const dates = ["2021-01-05T06:30:00.000Z","2021-01-06T06:30:00.000Z","2021-01-20T06:30:00.000Z","2021-02-09T06:30:00.000Z","2021-02-23T06:30:00.000Z","2021-02-16T06:30:00.000Z","2020-12-08T06:30:00.000Z","2020-12-15T06:30:00.000Z","2020-12-02T06:30:00.000Z","2020-12-09T06:30:00.000Z","2020-12-16T06:30:00.000Z"];
const grouped = dates.reduce((accumulator, date) => {
const parsed = new Date(date);
const year = parsed.getFullYear();
const month = parsed.getMonth();
const groupKey = `${month},${year}`;
accumulator[groupKey] = accumulator[groupKey] || {dates: []};
accumulator[groupKey].dates.push(parsed.getDay());
return accumulator;
}, {});
const result = Object.entries(grouped).map(([key, dates]) => {
const parts = key.split(',');
return {
month: parts[0],
year: parts[1],
dates: dates
};
});
console.log(result);
maybe do it in two passes
const dateArray = ["2021-01-05T06:30:00.000Z", "2021-01-06T06:30:00.000Z", "2021-01-20T06:30:00.000Z", "2021-02-09T06:30:00.000Z", "2021-02-23T06:30:00.000Z", "2021-02-16T06:30:00.000Z", "2020-12-08T06:30:00.000Z", "2020-12-15T06:30:00.000Z", "2020-12-02T06:30:00.000Z", "2020-12-09T06:30:00.000Z", "2020-12-16T06:30:00.000Z"];
const mapping = dateArray.reduce((initial, next) => {
const month = next.substring(5, 7);
const year = next.substring(0, 4);
const day = next.substring(8, 10);
initial[year] = initial[year] || {};
initial[year][month] = initial[year][month] || [];
initial[year][month].push(parseInt(day, 10));
return initial;
}, {});
const result = []
Object.keys(mapping).forEach(year => {
Object.keys(mapping[year]).forEach(month => {
result.push({
month,
year,
dates: mapping[year][month]
});
});
});
console.log(result);
One simple solution is to use an object to group by month and year like below:
const data = ["2021-01-05T06:30:00.000Z","2021-01-06T06:30:00.000Z",
"2021-01-20T06:30:00.000Z","2021-02-09T06:30:00.000Z",
"2021-02-23T06:30:00.000Z","2021-02-16T06:30:00.000Z",
"2020-12-08T06:30:00.000Z","2020-12-15T06:30:00.000Z",
"2020-12-02T06:30:00.000Z","2020-12-09T06:30:00.000Z",
"2020-12-16T06:30:00.000Z"];
function groupDates(dates) {
const groupedDates = {};
dates.forEach(d => {
const dt = new Date(d);
const date = dt.getDate();
const year = dt.getFullYear();
const month = dt.getMonth() + 1;
const key = `${year}-${month}`;
if (key in groupedDates) {
groupedDates[key].dates = [...groupedDates[key].dates, date];
} else {
groupedDates[key] = {
year,
month,
dates: [date],
};
}
});
return Object.values(groupedDates);
}
console.log(groupDates(data));
Here is a pure javascript solution without using any library. It is based on a simple O(n^2) runtime. But if you like to use some libraries for like binary search you can reduce it to O(nlogn).
The trick is to brick this task into smaller task as I did with functions getMonthYear (to convert string to object), compare and addDate:
data = ["2021-01-05T06:30:00.000Z","2021-01-06T06:30:00.000Z","2021-01-20T06:30:00.000Z","2021-02-09T06:30:00.000Z","2021-02-23T06:30:00.000Z","2021-02-16T06:30:00.000Z","2020-12-08T06:30:00.000Z","2020-12-15T06:30:00.000Z","2020-12-02T06:30:00.000Z","2020-12-09T06:30:00.000Z","2020-12-16T06:30:00.000Z"];
function categorize(data) {
// 2021-01-05T06:30:00.000Z => {month:"01", year:"2021", date:"05"}
function getMonthYear(str) {
var datePart = str.toString().trim().split("T")[0];
var datePartArr = datePart.split("-");
return {month:datePartArr[1], year:datePartArr[0], date:datePartArr[2]};
}
// testing
//var ans = getMonthYear("2021-01-06T06:30:00.000Z");
//console.log(ans);
// comparing two items to see if they have the same year and month
function compare(item1, item2) {
return (item1.month == item2.month) && (item1.year == item2.year);
}
// testing
//var ans = compare({month:"04", year:"2021"}, {month:"03", year:"2021"});
//console.log(ans);
// adding a date to the list of dates
function addDate(dateList, dateNumber) {
for(var i in dateList) {
if (dateList[i] == dateNumber) return;
}
dateList.push(dateNumber);
}
// testing
/*var ans = [2,4];
addDate(ans, 4);
console.log(ans);*/
// Now lets build the answer by looping over
// --------------------------------------------
var list = []; // the final answer list
data.forEach(function(str){
var item = getMonthYear(str);
var itemMatched = false;
// now lopping over the list to see if it has any match
for(var i in list) {
if (compare(item, list[i])) { // matched found
itemMatched = true;
addDate(list[i].date, item.date);
break;
}
}
// item had no match, add it as a new item to list
if (!itemMatched) {
list.push({
month: item.month,
year: item.year,
date: [item.date]
});
}
});
return list;
}
var ans = categorize(data);
console.log(ans);
Here is link to jsfiddle
So i have two lists.
List A contains a list of all dates of a specified month. list B contains a sequence of 1 and 0´s. If i want to check if date from list A is equal to 1 or 0 corresponding to the position in list B, How should i approach this?.
The idea is to check if day 1,2,3.. and so on is value 1 or 0 from List B..
Example 2020-02-01 = 1 or 0...
var listDate = [];
var startDate ='2020-02-01';
var endDate = '2020-02-29';
var dateMove = new Date(startDate);
var strDate = startDate;
while (strDate < endDate){
var strDate = dateMove.toISOString().slice(0,10);
var dayCount = listDate.length;
listDate.push(strDate);
dateMove.setDate(dateMove.getDate()+1);
};
console.log(dayCount + 1)
console.log(listDate)
Then i have another list that contains a sequence of 1 and 0 ´s.
var str = "1100000110000011000001100000100";
var res = str.split("");
var n = str.length;
console.log(n)
console.log(res)
listDate.filter((_,i) => str[i]==='1')
will give you the dates where you have a 1 in the 'binary list'
listDate.map((date,i) => [date,str[i]])
will give you a new list with sublists [date,"1 or 0"]
listDate.map((date,i) => [date,str[i]==='1'])
will give you a new list with sublists [date,true or false]
Like this?
const res = "1100000110000011000001100000100".split("");
var listDate = [];
var startDate ='2020-02-01';
var endDate = '2020-02-29';
var dateMove = new Date(startDate);
var strDate = startDate;
while (strDate < endDate){
var strDate = dateMove.toISOString().slice(0,10);
var dayCount = listDate.length;
listDate.push(strDate);
dateMove.setDate(dateMove.getDate()+1);
};
// code based on day number rather than the place in the array
listDate.forEach(dt => console.log(dt,res[dt.split("-")[2]-1]))
let weekdays = listDate.filter(dt => res[dt.split("-")[2]-1]==="0")
let weekends = listDate.filter(dt => res[dt.split("-")[2]-1]==="1")
console.log(weekends)
// same code based on index
listDate.forEach((dt,i) => console.log(dt,res[i]))
weekdays = listDate.filter((dt,i) => res[i]==="0")
weekends = listDate.filter((dt,i) => res[i]==="1")
console.log(weekends)
My javascript array like that.
var datearray = [
"2016-01-13",
"2016-01-18",
"2016-01-30",
"2016-02-13",
"2016-02-18",
"2016-02-28",
"2016-03-13",
"2016-03-23",
"2016-03-30",
"2016-04-13",
"2016-04-18",
"2016-04-30",
"2016-05-13",
"2016-05-18",
"2016-05-28",
"2016-06-13",
"2016-06-23",
"2016-06-30",
"2016-08-22"
]
but my searching dates are startDate = 2015-12-01; and endDate = 2016-09-30; I want to get new date array between above startDate and endDate. This new array will display like this,
var newOjArray = [
{"2015-12":"0"},
{"2016-01":"3"},
{"2016-02":"3"},
{"2016-03":"3"},
{"2016-04":"3"},
{"2016-05":"3"},
{"2016-06":"3"},
{"2016-07":"0"},
{"2016-08":"1"},
{"2016-09":"0"}
];
values meaning total count of considering date range. How I created It.
A complete proposal. With an array with the wanted grouped result.
function getGroupedData(dates, from, to) {
function pad(s, n) { return s.toString().length < n ? pad('0' + s, n) : s; }
var temp = Object.create(null),
result = [],
fromYear = +from.slice(0, 4),
fromMonth = +from.slice(5, 7),
toYear = +to.slice(0, 4),
toMonth = +to.slice(5, 7),
o, k;
datearray.forEach(function (d) {
var k = d.slice(0, 7);
temp[k] = (temp[k] || 0) + 1;
});
while (true) {
k = pad(fromYear, 4) + '-' + pad(fromMonth, 2);
o = {};
o[k] = (temp[k] || 0).toString();
result.push(o);
if (fromYear === toYear && fromMonth === toMonth) {
break;
}
fromMonth++;
if (fromMonth > 12) {
fromMonth = 1;
fromYear++;
}
}
return result;
}
var datearray = ["2016-01-13", "2016-01-18", "2016-01-30", "2016-02-13", "2016-02-18", "2016-02-28", "2016-03-13", "2016-03-23", "2016-03-30", "2016-04-13", "2016-04-18", "2016-04-30", "2016-05-13", "2016-05-18", "2016-05-28", "2016-06-13", "2016-06-23", "2016-06-30", "2016-08-22"];
console.log(getGroupedData(datearray, '2015-12-01', '2016-09-30'));
You can use Array.filter to filter through this array. Taking advantage of your particular date format, we do not need to do any date arithmetic, we can simply compare dates as strings and use localeCompare() to compare them:
var datearray = [
"2016-01-13",
"2016-01-18",
"2016-01-30",
"2016-02-13",
"2016-02-18",
"2016-02-28",
"2016-03-13",
"2016-03-23",
"2016-03-30",
"2016-04-13",
"2016-04-18",
"2016-04-30",
"2016-05-13",
"2016-05-18",
"2016-05-28",
"2016-06-13",
"2016-06-23",
"2016-06-30",
"2016-08-22"
];
var startDate = "2015-12-01";
var endDate = "2016-01-30";
var filteredArray = datearray.filter(function(item){
return item.localeCompare( startDate ) > -1 && endDate.localeCompare( item ) > -1;
});
console.log( filteredArray );
Now, you have the filteredArray and you can simply iterate through it to count the number of dates falling in a month.
You may try this:
Underscore.js has been used to manipulate data.
var datearray=["2016-01-13","2016-01-18","2016-01-30","2016-02-13","2016-02-18","2016-02-28","2016-03-13","2016-03-23","2016-03-30","2016-04-13","2016-04-18","2016-04-30","2016-05-13","2016-05-18","2016-05-28","2016-06-13","2016-06-23","2016-06-30","2016-08-22"];
var boxingDay = new Date("12/01/2015");
var nextWeek = new Date("09/30/2016");
function getDates( d1, d2 ){
var oneDay = 24*3600*1000;
for (var d=[],ms=d1*1,last=d2*1;ms<last;ms+=oneDay){
var new_Date=new Date(ms);
d.push( new_Date.getFullYear()+"-"+("0" + (new_Date.getMonth() + 1)).slice(-2) );
}
return d;
}
var x=[];
_.each(datearray, function(e){x.push(e.substring(0, 7));});
var z= _.uniq(getDates( boxingDay, nextWeek ));
var f=x.concat(_.uniq(getDates( boxingDay, nextWeek )));
document.getElementById("xx").innerHTML=JSON.stringify(_.countBy(f));
<script src="http://underscorejs.org/underscore-min.js"></script>
<div id="xx"></div>
If you looking for a more ES6 way then check it out:
var dateArray = ["2016-01-13", "2016-01-18", "2016-01-30", "2016-02-13", "2016-02-18", "2016-02-28", "2016-03-13", "2016-03-23", "2016-03-30", "2016-04-13", "2016-04-18", "2016-04-30", "2016-05-13", "2016-05-18", "2016-05-28", "2016-06-13", "2016-06-23", "2016-06-30", "2016-08-22"];
var group = {};
dateArray.forEach(date =>
group[(date = date.substr(0, 7))] =
(group[date] || []).concat(date)
);
var result = Object.keys(group)
.map(date => ({
[date]: group[date].length
}));
console.log(result)
If your date format is as the date array then the easiest way would be to use substr if the length is not constant then you can split it by spacer and then get the two first values. And if it's totally a date string you can create a date from this and convert it to your desired string as key of your object.