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.
Related
I need to create an array of results, to create an easy example a reduce my function.
let startDate = new Date("2022-04-05"); // starting date
let endDate = new Date("2022-04-06"); // ending date
let result = await cycleThroughDays(startDate, endDate);
console.log("result", result)
async function cycleThroughDays(startDate, endDate) {
let res = [];
for (let currentDate = startDate; currentDate <= endDate; currentDate.setDate(currentDate.getDate() + 1)) {
console.log(currentDate)
res.push(currentDate);
}
console.log(res)
return res;
}
The output is:
2022-04-05T00:00:00.000Z
2022-04-06T00:00:00.000Z
[ 2022-04-07T00:00:00.000Z, 2022-04-07T00:00:00.000Z ]
result [ 2022-04-07T00:00:00.000Z, 2022-04-07T00:00:00.000Z ]
I expect an array like
result [ 2022-04-05T00:00:00.000Z, 2022-04-06T00:00:00.000Z ]
but I get
result [ 2022-04-07T00:00:00.000Z, 2022-04-07T00:00:00.000Z ]
You need to create a separate variable to hold the current date, and increment that variable within the loop. Try this.
let startDate = new Date("2022-04-05"); // starting date
let endDate = new Date("2022-04-06"); // ending date
let result = await cycleThroughDays(startDate, endDate);
console.log("result", result)
async function cycleThroughDays(startDate, endDate) {
let res = [];
let current = new Date(startDate);
while (current <= endDate) {
console.log(current);
res.push(current);
current.setDate(current.getDate() + 1);
}
console.log(res);
return res;
}
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)
I have an array of dates such as :
test = [ '2018-07-18', '2018-07-19', '2018-07-21', '2018-07-23', '2018-07-24', '2018-07-26'];
And I want to return an array of sub arrays of consecutive dates like this:
result = [['2018-07-18', '2018-07-19'], ['2018-07-21'], ['2018-07-23', '2018-07-24'], ['2018-07-26']]
I'm trying to write a snippet code:
const moment = require('moment');
let visited = [];
const alpha = test.reduce((accumlator, current_date, current_index, array) => {
let start_date = current_date;
let successive_date = array[current_index + 1];
visited.push(start_date);
if(successive_date && moment(successive_date).diff(moment(start_date), 'days') === 1
&& visited.includes(successive_date) === false) {
accumlator.concat(start_date);
accumlator.concat(successive_date);
}
if(successive_date && moment(successive_date).diff(moment(start_date), 'days') !== 1
&& visited.includes(successive_date) === false) {
accumlator.concat(successive_date);
}
return accumlator;
}, []);
console.log('alpha: ', alpha);
The result when using concat was:
alpha: []
I used push() and it returns an array such test:
alpha: [ '2018-07-18','2018-07-19','2018-07-21','2018-07-23','2018-07-23','2018-07-24''2018-07-26' ]
How can I fix this in order to get the result such as mentioned above?
You can try with:
test.reduce((acc, date) => {
const group = acc[acc.length - 1];
if (moment(date).diff(moment(group[group.length - 1] || date), 'days') > 1) {
acc.push([date])
} else {
group.push(date);
}
return acc;
}, [[]])
Output:
[
[
"2018-07-18",
"2018-07-19"
],
[
"2018-07-21"
],
[
"2018-07-23",
"2018-07-24"
],
[
"2018-07-26"
]
]
Th following helps, if the order of the dates in the array is not maintained. For example, '2018-07-18', '2018-07-19', '2018-07-17' are consecutive but scattered at the start and end of the array.
var test = [ '2018-07-18', '2018-07-19', '2018-07-21', '2018-07-23', '2018-07-24', '2018-07-26', '2018-07-17'], dateformat = "YYYY-MM-DD";
var result = test.reduce(function(acc,val){
var present, date = moment(val,dateformat);
acc.forEach(function(arr,index){
if(present) return;
if(arr.indexOf(date.clone().subtract(1,'day').format(dateformat))>-1 || arr.indexOf(date.clone().add(1,'day').format(dateformat))>-1)
{
present = true;
arr.push(val);
}
});
if(!present) acc.push([val]);
return acc;
},[]);
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
You can use this function but dates should be in sorted order.
function get_relative_dates(dates){
var format = 'YYYY-MM-DD';
var newDate = [];
dates.forEach(function(date){
var lastArr, lastDate;
if(newDate.length){
lastArr = newDate[newDate.length -1];
if(!lastArr.length)
lastArr.push(date);
else{
var lastDate = lastArr[lastArr.length -1];
if(moment(lastDate, format).add(1,'d').format(format) == date)
lastArr.push(date);
else
newDate.push([date]);
}
}
else
newDate.push([date]);
});
return newDate;
}
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 ) );