How to get regular interval count - javascript

So I have the data in below format
const data = [
{ date: '01-07-2019' },
{ date: '02-07-2019' },
{ date: '03-07-2019' },
{ date: '04-07-2019' },
{ date: '05-07-2019' },
{ date: '06-07-2019' },
{ date: '07-07-2019' },
{ date: '08-07-2019' },
{ date: '09-07-2019' },
{ date: '10-07-2019' },
{ date: '15-07-2019' },
{ date: '16-07-2019' },
{ date: '20-07-2019' },
{ date: '21-07-2019' },
{ date: '22-07-2019' },
{ date: '23-07-2019' }
]
So I have to count the regular interval dates. For example on date { date: '10-07-2019' }, { date: '20-07-2019' } and on { date: '23-07-2019' } it breaks so count should be again started with 1.
const ouput = [{
startDate: '01-07-2019',
endDate: '10-07-2019',
count: 10
}, {
startDate: '15-07-2019',
endDate: '16-07-2019',
count: 2
}, {
startDate: '20-07-2019',
endDate: '23-07-2019',
count: 4
}]
I did that
const output = Object.values(data.reduce((a, { startDate, endDate }, i) => {
const startTime = moment(data[i].date)
const endTime = moment(data[i + 1] && data[i + 1].date)
if (moment.duration(endTime.diff(startTime)).asDays === 1) {
a.startDate = startDate
a.startDate = endDate
}
a.count++;
return a;
}, {}));
But it is not giving what I expect. Please help.

I would do that with a function generator to handle the desired aggregation.
The below code will loop the dates, take a pair, check whether the start date exists, update the end date and automatically yield the value if necessary.
Comments are directly in the code below, the code assumes the initial array is already sorted as the example you mentioned.
As a side note, you're actually including the last date in the count, while, effectively, it should be one day less than your count. Further comments about that are available below in the function generator code.
const data = [
{ date: '01-07-2019' },
{ date: '02-07-2019' },
{ date: '03-07-2019' },
{ date: '04-07-2019' },
{ date: '05-07-2019' },
{ date: '06-07-2019' },
{ date: '07-07-2019' },
{ date: '08-07-2019' },
{ date: '09-07-2019' },
{ date: '10-07-2019' },
{ date: '15-07-2019' },
{ date: '16-07-2019' },
{ date: '20-07-2019' },
{ date: '21-07-2019' },
{ date: '22-07-2019' },
{ date: '23-07-2019' }
];
// Counts intervals of consecutive dates.
function* countIntervals(dates) {
// declare an initial accumulator.
let acc = {
count: 0
};
for (let i = 0; i < dates.length; i++) {
// get the currently looped value and the next one.
const [curr, next] = [moment(dates[i].date, 'DD-MM-YYYY'), dates[i+1] ? moment(dates[i+1].date, 'DD-MM-YYYY') : null];
// if the current date and next days are valid and if the difference in days between them is 1..
if (curr && next && (next.diff(curr, "days") === 1)) {
// Then keep track of the start date if not set, update the end date and increase the count of days.
acc.startDate = acc.startDate || dates[i].date, acc.endDate = dates[i+1].date, acc.count++;
}
else {
// otherwise, if the accumulator has a start date, yield the value.
if (acc && acc.startDate) {
acc.count++; // <-- comment this if you don't want the last date to be included.
yield Object.assign({}, acc);
// and init again the accumulator.
acc = {
count: 0
};
}
}
}
// if the loop is finished and the progression continued, yield the current accumulator.
if (acc.startDate) yield acc;
}
// usage...
const intervals = [...countIntervals(data)];
console.log(intervals);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Here you go, Try this
const data = [
{ date: "01-07-2019" },
{ date: "02-07-2019" },
{ date: "03-07-2019" },
{ date: "04-07-2019" },
{ date: "05-07-2019" },
{ date: "06-07-2019" },
{ date: "07-07-2019" },
{ date: "08-07-2019" },
{ date: "09-07-2019" },
{ date: "10-07-2019" },
{ date: "15-07-2019" },
{ date: "16-07-2019" },
{ date: "20-07-2019" },
{ date: "21-07-2019" },
{ date: "22-07-2019" },
{ date: "23-07-2019" }
];
function to parse date
function parseDate(input) {
var parts = input.split("-");
// new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
return new Date(parts[2], parts[1] - 1, parts[0]); // Note: months are 0-based
}
function to get date difference
function dateDiff(date1, date2) {
date1 = parseDate(date1);
date2 = parseDate(date2);
let diffTime = Math.abs(date2.getTime() - date1.getTime());
let diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays;
}
Required output
const output = data.reduce(function(resultSet, currentValue, currentIndex, arr) {
if (resultSet.length == 0) {
resultSet.push({
startDate: currentValue.date,
endDate: currentValue.date,
count: 1
});
}
else{
let dateDiffrence = dateDiff(resultSet[resultSet.length-1].endDate, currentValue.date);
console.log(dateDiffrence);
if(dateDiffrence == 1){
resultSet[resultSet.length-1].endDate = currentValue.date;
resultSet[resultSet.length-1].count++;
}else{
resultSet.push({
startDate: currentValue.date,
endDate: currentValue.date,
count: 1
});
}
}
return resultSet;
}, []);

Yet another possible solution.
const parseDate = (str) => {
const [d, m, y] = str.split('-');
return +new Date(y, m - 1, d)
}
const output = data.reduce((a, {
date
}, i) => {
const cur = parseDate(date);
const lastDate = data[i - 1] && data[i - 1].date || date;
const last = parseDate(lastDate || date);
if (cur - last > 1000 * 60 * 60 * 24) a.push({count: 0});
const {
startDate = date,
count
} = a.pop();
a.push({
startDate,
endDate: date,
count: count + 1
})
return a;
}, [{
count: 0
}])
console.log (output)
<script>
const data = [
{ date: '01-07-2019' },
{ date: '02-07-2019' },
{ date: '03-07-2019' },
{ date: '04-07-2019' },
{ date: '05-07-2019' },
{ date: '06-07-2019' },
{ date: '07-07-2019' },
{ date: '08-07-2019' },
{ date: '09-07-2019' },
{ date: '10-07-2019' },
{ date: '15-07-2019' },
{ date: '16-07-2019' },
{ date: '20-07-2019' },
{ date: '21-07-2019' },
{ date: '22-07-2019' },
{ date: '23-07-2019' }
]</script>

If you construct UTC dates there will be no need to use moment.js. With UTC every day is 24 hours and DST does not apply. This solution features a boilerplate function to handle the creation of the UTC date from your date string format.
const data = [
{ date: '01-07-2019' },
{ date: '02-07-2019' },
{ date: '03-07-2019' },
{ date: '04-07-2019' },
{ date: '05-07-2019' },
{ date: '06-07-2019' },
{ date: '07-07-2019' },
{ date: '08-07-2019' },
{ date: '09-07-2019' },
{ date: '10-07-2019' },
{ date: '15-07-2019' },
{ date: '16-07-2019' },
{ date: '20-07-2019' },
{ date: '21-07-2019' },
{ date: '22-07-2019' },
{ date: '23-07-2019' }
];
const ONE_DAY = 1000 * 60 * 60 * 24;
function dateStrToUTC(dateStr) {
const dateParts = dateStr.split('-');
const utcDate = new Date();
utcDate.setUTCFullYear(dateParts[2]);
utcDate.setUTCMonth(dateParts[1] - 1);
utcDate.setUTCDate(dateParts[0]);
utcDate.setUTCHours(0);
utcDate.setUTCMinutes(0);
utcDate.setUTCSeconds(0);
utcDate.setUTCMilliseconds(0);
return utcDate;
}
function getRegularIntervals(accumulator, currentValue) {
const index = accumulator.length - 1;
let daysPassed = 0;
if (index > -1) {
daysPassed = (dateStrToUTC(currentValue.date) - dateStrToUTC(accumulator[index].endDate)) / ONE_DAY;
}
if (index > -1 && 1 == daysPassed) {
accumulator[index].endDate = currentValue.date;
accumulator[index].count++;
} else {
accumulator.push({
startDate: currentValue.date,
endDate: currentValue.date,
count: 1
});
}
return accumulator;
}
const output = data.reduce(getRegularIntervals, []);
console.log(output);
Output as expected:
[
{
"startDate": "01-07-2019",
"endDate": "10-07-2019",
"count": 10
},
{
"startDate": "15-07-2019",
"endDate": "16-07-2019",
"count": 2
},
{
"startDate": "20-07-2019",
"endDate": "23-07-2019",
"count": 4
}
]

I liked your approach of using reduce function.
Going with the same, I just added some more logic in there and here is the final code.
// initially lets assume first date is the start as well as end date
var dateIntervalObject = {
startDate: data[0].date,
endDate: data[0].date,
count: 1
};
var result = data.reduce((resultArray, obj, i) => {
if(i > 0) {
var startTime = moment(dateIntervalObject.endDate, "DD-MM-YYYY");
var endTime = moment(obj.date, "DD-MM-YYYY");
if (endTime.diff(startTime, 'days') === 1) {
dateIntervalObject.endDate = obj.date;
dateIntervalObject.count += 1;
// remove the latest object in array, to replace with new
resultArray.pop();
} else {
dateIntervalObject = {
startDate: obj.date,
endDate: obj.date,
count: 1
};
}
// push the date Interval object in the array
resultArray.push(dateIntervalObject);
}
return resultArray;
}, [dateIntervalObject]);
console.log('result: ',result);
Note:
When initialState of the accumulator is passed to reduce function it starts iterating from 0th index, which in our case have already been initialized in the dateIntervalObject and therefore the first iteration with index value 0 is skipped.
Also, if the interval is not changing, we don't need to add another object to our result array but instead update the end date of the last element of our result array. Therefore, first pop and then push to just update the end date and count value.
Hope this helps!

Related

How do I loop through dates in momentJS such that it will happen twice a month?

I want to loop from Jan 1, 2022 until June 14, 2022 (or any given date) using momentJS or LuxonJS such that it happens twice in a given month. This is my code:
const frequency = [];
for (var m = moment('2022-01-01'); m.isSameOrBefore('2022-06-14'); m.add(15, 'days')) {
frequency.push({
dueDate: moment(m).format('YYYY-MM-DD'),
});
}
This is the Result:
frequency : [
{ dueDate: '2022-01-01' },
{ dueDate: '2022-01-16' },
{ dueDate: '2022-01-31' },
{ dueDate: '2022-02-15' },
{ dueDate: '2022-03-02' },
{ dueDate: '2022-03-17' },
{ dueDate: '2022-04-01' },
{ dueDate: '2022-04-16' },
{ dueDate: '2022-05-01' },
{ dueDate: '2022-05-16' },
{ dueDate: '2022-05-31' }
]
This is not my desired result because it happens thrice in January, once in February, and thrice in May.
I want the loop to consider the number of days in a month so that it loops twice each month.
My desired result is something similar to this but not specifically this as long as it loops twice in a month.
desired : [
{ dueDate: '2022-01-01' },
{ dueDate: '2022-01-16' },
{ dueDate: '2022-02-01' },
{ dueDate: '2022-02-16' },
{ dueDate: '2022-03-01' },
{ dueDate: '2022-03-16' },
{ dueDate: '2022-04-01' },
{ dueDate: '2022-04-16' },
{ dueDate: '2022-05-01' },
{ dueDate: '2022-05-16' },
{ dueDate: '2022-06-01' },
]
You can use the .daysInMonth method to get the current amount of days in the current iterated month and add by the half amount of days.
let frequency = [];
for (var m = moment('2022-01-01'); m.isSameOrBefore('2022-06-14'); m.add(1, 'month')) {
frequency.push({
dueDate: moment(m).format('YYYY-MM-DD'),
});
frequency.push({
dueDate: moment(m).add(Math.floor(m.daysInMonth() / 2), 'days').format('YYYY-MM-DD'),
});
}
Notice I also increment by month but push twice per month. It makes the intent much more clear.
Result:
[
{ "dueDate": "2022-01-01" },
{ "dueDate": "2022-01-16" },
{ "dueDate": "2022-02-01" },
{ "dueDate": "2022-02-15" },
{ "dueDate": "2022-03-01" },
{ "dueDate": "2022-03-16" },
{ "dueDate": "2022-04-01" },
{ "dueDate": "2022-04-16" },
{ "dueDate": "2022-05-01" },
{ "dueDate": "2022-05-16" },
{ "dueDate": "2022-06-01" },
{ "dueDate": "2022-06-16" }
]
You don't need a date library for that, as it can be done with string manipulation.
You could define a 1-to-1 mapping between dates and numbers, such that two consecutive numbers map to one month (either day 01 or day 16), and days of a month are mapped back accordingly.
Then it becomes a matter of iterating a range of numbers and map those back to date strings:
function twicePerMonth(start, end) {
const toNumber = s => (([y, m, d]) => 24*y+2*m+(d>1)+(d>16)-2)(s.split("-"));
const toString = n => [~~(n / 24), ((n % 24) >> 1) + 1, (n % 2) * 15 + 1]
.join("-").replace(/\b\d\b/g, "0$&");
start = toNumber(start);
return Array.from({length: toNumber(end) - start}, (_, i) => ({
dueDate: toString(start + i)
}));
}
const result = twicePerMonth('2022-01-01', '2022-06-13');
console.log(result);

How to map array elements in JavaScript

Only elements that have a value greater than or equal to the threshold must be kept in the array. Then a new array will have to be created which will contain several objects. Each of these objects will have two properties, the start and the end.
If there are several elements in a row (which have a timestamp 10 minutes apart), they will be grouped in the same object. Where the start value will be the timestamp of the first element and the end value will be the timestamp value of the last element of the group plus 10 min.
If there are not several elements followed, the start value will be the timestamp and the end will be the timestamp plus 10 minutes.
const data = [{
timestamp: '2021-11-23T14:00:00+0000',
amount: 21
},
{
timestamp: '2021-11-23T14:10:00+0000',
amount: 27
},
{
timestamp: '2021-11-23T14:20:00+0000',
amount: 31
},
{
timestamp: '2021-11-23T14:30:00+0000',
amount: 29
},
{
timestamp: '2021-11-23T14:40:00+0000',
amount: 18
},
{
timestamp: '2021-11-23T14:50:00+0000',
amount: 17
},
{
timestamp: '2021-11-23T15:00:00+0000',
amount: 25
},
{
timestamp: '2021-11-23T15:10:00+0000',
amount: 21
}
]
const threshold = 25
const aboveThreshold = data.filter(element => element.amount >= threshold)
const workSchedule = []
for (let i = 0; i < aboveThreshold.length; i++) {
if (i === 0) {
workSchedule.push({
start: aboveThreshold[i].timestamp,
end: aboveThreshold[i + 1].timestamp
})
}
if (i > 0 && i < aboveThreshold.length - 1) {
if (aboveThreshold[i].timestamp.slice(11, 13) === aboveThreshold[i + 1].timestamp.slice(11, 13)) {
workSchedule.push({
start: aboveThreshold[i].timestamp,
end: aboveThreshold[i + 1].timestamp
})
}
}
if (i === aboveThreshold.length - 1) {
workSchedule.push({
start: aboveThreshold[i].timestamp,
end: aboveThreshold[i].timestamp
})
}
}
console.log(workSchedule)
But the end result I want is the following:
[
{
start: '2021-11-23T14:10:00+0000',
end: '2021-11-23T14:40:00+0000'
},
{
start: '2021-11-23T15:00:00+0000',
end: '2021-11-23T15:10:00+0000'
}
]
I hope I was clear 😬 and is there a simpler and easier to understand/read approach than what I've done so far?
You can apply a simple reduce function to get the result you want with a little bit of help from Date object. Here is a solution:
const aboveThreshold = data.filter(element => element.amount >= threshold);
const nws = aboveThreshold.reduce((acc, v) => {
const end = new Date(Date.parse(v.timestamp) + 600000);
if (acc.length === 0) return [{ start: v.timestamp, end: end.toISOString() }];
let diff = Date.parse(v.timestamp) - Date.parse(acc[acc.length - 1].end);
// checks if the difference is less than 10 minutes
if (diff <= 10 * 60 * 1000) {
acc[acc.length - 1].end = end.toISOString();
} else {
acc.push({ start: v.timestamp, end: end.toISOString() });
}
return acc
}, []);
Check out Reduce Documentation.
This is the result it gives with your data
[{
end: "2021-11-23T14:40:00.000Z",
start: "2021-11-23T14:10:00+0000"
}, {
end: "2021-11-23T15:10:00.000Z",
start: "2021-11-23T15:00:00+0000"
}]

Filter array by date and value

I'm trying filter an array but it's returning empty, I'm trying to get it to return an array with where the date is in the previous 30 minutes and the value is over 15.
Let's say the current time is 19:45:
let transactions = [
{ value: "50.00", date: "2020-08-03T11:52:28.876Z" },
{ value: "13.10", date: "2020-08-03T11:57:32.900Z" },
{ value: "12.11", date: "2020-08-03T12:23:06.379Z" },
{ value: "12.89", date: "2020-08-03T14:20:41.720Z" },
{ value: "12.89", date: "2020-08-03T19:30:41.720Z" },
{ value: "22.89", date: "2020-08-03T19:34:41.720Z" },
{ value: "50.00", date: "2020-08-03T19:40:41.720Z" }
];
const THIRTY_MINUTES = 30 * 60 * 1000;
const isLastThirtyMins = transactions
.map(
transaction =>
new Date().getTime() - new Date(transaction.date).getTime() <
THIRTY_MINUTES
)
.filter(transaction => transaction.value >= 15);
console.log(isLastThirtyMins);
// []
I'm trying to get it to return these 2 items:
{ value: "22.89", date: "2020-08-03T19:34:41.720Z" }
{ value: "50.00", date: "2020-08-03T19:40:41.720Z" }
Use filter instead of map
const isLastThirtyMins = transactions
.filter(transaction => new Date().getTime() - new Date(transaction.date).getTime() < THIRTY_MINUTES)
.filter(transaction => parseFloat(transaction.value) >= 15);
Or better, call filter only once:
const isLastThirtyMins = transactions
.filter(transaction =>
(new Date().getTime() - new Date(transaction.date).getTime() < THIRTY_MINUTES) &&
(parseFloat(transaction.value) >= 15));
const isLastThirtyMins = transactions
.filter(
transaction =>
new Date().getTime() - new Date(transaction.date).getTime() <
THIRTY_MINUTES
);
Exaplaination:
What you where doing is mapping each element in you array to new Date().getTime() - new Date(transaction.date).getTime() < THIRTY_MINUTES which is a boolean. Thus, the return value of map would be something like [true, false, false, true ...] and then you are trying to filter this returned array by transaction.value, but as you can see, transaction now is a boolean and not the real transaction and it does not have value property.

How to add count for the same week using reduce JavaScript?

I am trying to implement a function using reduce that allows me to group an array of objects { date: '2019-03-11', count: 8 } by weeks. So far, I was able to group dates by weeks but I am having trouble to add together count if the date falls in the same week.
const dates = [
{ date: '2019-03-11', count: 8 },
{ date: '2019-03-12', count: 7 },
{ date: '2019-03-09', count: 6 },
{ date: '2019-02-27', count: 10 },
{ date: '2019-02-26', count: 11 },
{ date: '2019-02-22', count: 12 },
{ date: '2019-04-21', count: 3 },
{ date: '2019-04-18', count: 2 },
{ date: '2019-04-17', count: 4 },
{ date: '2019-04-19', count: 5 }
];
Date.prototype.getWeek = function() {
const onejan = new Date(this.getFullYear(), 0, 1);
return Math.ceil(((this - onejan) / 86400000 + onejan.getDay() + 1) / 7);
};
const groups = dates.reduce(function(acc, item) {
const today = new Date(item.date);
const weekNumber = today.getWeek(today);
// check if the week number exists
if (typeof acc[weekNumber] === 'undefined') {
acc[weekNumber] = [];
}
acc[weekNumber].push(item.date, item.count);
return acc;
}, {});
console.log(groups);
Current Result
Desired Result
[
{ weekStart: '2019-02-17', count: 12 },
{ weekStart: '2019-02-24', count: 21 },
{ weekStart: '2019-03-03', count: 6 },
{ weekStart: '2019-03-10', count: 15 },
{ weekStart: '2019-04-14', count: 11 },
{ weekStart: '2019-04-21', count: 21 }
]
where weekStart is the first date of the week (Sunday) by which it was grouped
SOLUTION
const dates = [
{ date: '2019-02-24', count: 10 },
{ date: '2019-02-25', count: 11 },
{ date: '2019-02-26', count: 12 },
{ date: '2019-03-09', count: 8 },
{ date: '2019-03-10', count: 7 },
{ date: '2019-03-11', count: 6 },
{ date: '2019-04-14', count: 3 },
{ date: '2019-04-15', count: 2 },
{ date: '2019-04-16', count: 4 },
{ date: '2019-04-22', count: 5 }
];
/**
* Returns the week number for this date. dowOffset is the day of week the week
* "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday),
* the week returned is the ISO 8601 week number.
* #param int dowOffset
* #return int
*/
Date.prototype.getWeek = function(dowOffset) {
/*getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.epoch-calendar.com */
dowOffset = typeof dowOffset == 'int' ? dowOffset : 0; //default dowOffset to zero
var newYear = new Date(this.getFullYear(), 0, 1);
var day = newYear.getDay() - dowOffset; //the day of week the year begins on
day = day >= 0 ? day : day + 7;
var daynum =
Math.floor(
(this.getTime() -
newYear.getTime() -
(this.getTimezoneOffset() - newYear.getTimezoneOffset()) * 60000) /
86400000
) + 1;
var weeknum;
//if the year starts before the middle of a week
if (day < 4) {
weeknum = Math.floor((daynum + day - 1) / 7) + 1;
if (weeknum > 52) {
nYear = new Date(this.getFullYear() + 1, 0, 1);
nday = nYear.getDay() - dowOffset;
nday = nday >= 0 ? nday : nday + 7;
/*if the next year starts before the middle of
the week, it is week #1 of that year*/
weeknum = nday < 4 ? 1 : 53;
}
} else {
weeknum = Math.floor((daynum + day - 1) / 7);
}
return weeknum;
};
function getWeekStart(date) {
var offset = new Date(date).getDay();
return new Date(new Date(date) - offset * 24 * 60 * 60 * 1000)
.toISOString()
.slice(0, 10);
}
function groupWeeks(dates) {
const groupsByWeekNumber = dates.reduce(function(acc, item) {
const today = new Date(item.date);
const weekNumber = today.getWeek();
// check if the week number exists
if (typeof acc[weekNumber] === 'undefined') {
acc[weekNumber] = [];
}
acc[weekNumber].push(item);
return acc;
}, []);
return groupsByWeekNumber.map(function(group) {
return {
weekStart: getWeekStart(group[0].date),
count: group.reduce(function(acc, item) {
return acc + item.count;
}, 0)
};
});
}
console.log(groupWeeks(dates));
You could take the weekday as offset and subtract the milliseconds from the given date.
Reducing works with a callback and a clsoure over the key with the week start date.
(m, { date, count }) => // outer callback with map and object
(k => m.set(k, (m.get(k) || 0) + count)) // closure over k and updating the count in map
(getWeekStart(date)) // get value for k
function getWeekStart(date) {
var offset = new Date(date).getDay();
return new Date(new Date(date) - offset * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
}
const
dates = [{ date: '2019-03-11', count: 8 }, { date: '2019-03-12', count: 7 }, { date: '2019-03-09', count: 6 }, { date: '2019-02-27', count: 10 }, { date: '2019-02-26', count: 11 }, { date: '2019-02-22', count: 12 }, { date: '2019-04-21', count: 3 }, { date: '2019-04-18', count: 2 }, { date: '2019-04-17', count: 4 }, { date: '2019-04-19', count: 5 }],
result = Array.from(
dates.reduce((m, { date, count }) =>
(k => m.set(k, (m.get(k) || 0) + count))(getWeekStart(date)),
new Map),
([date, count]) => ({ date, count })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Filling array of missing values with respect to another array

Need to fill the values for missing dates.
I'm having an array as follows,
// actual array
var array1 = [{
date: "2017-11-07",
value: 23
},
{
date: "2017-11-05",
value: 30
},
{
date: "2017-11-04",
value: 24
},
{
date: "2017-11-02",
value: 23
}];
I need the filled array like the below,
// expected result
var array2 = [{
date: "2017-11-01",
value: 23
},
{
date: "2017-11-02",
value: 23
},
{
date: "2017-11-03",
value: 23
},
{
date: "2017-11-04",
value: 24
},
{
date: "2017-11-05",
value: 30
},
{
date: "2017-11-06",
value: 30
},
{
date: "2017-11-07",
value: 23
}];
Please advise me to how to make a loop to add the missing values with previous date value.
At first its hard to work with a datestrig, lets define some conversion functions:
const toDate = str => ( split => new Date(split[0], split[1] - 1, split[2]) )(str.split("-")),
toString = date => date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(),
DAY = 1000 * 60 * 60 * 24;
So then its probably good to sort the array, and we can store the real dates already:
array1.sort((a,b) => {
a.time = toDate(a.date);
b.time = toDate(b.date);
return a.time - b.time;
});
So now we just need to fill in the gaps:
const add = [];
array1.reduce( (before, after, i) => {
for(let time = +before.time + DAY; time < after.time; time += DAY)
add.push({ value: before.value, time, date: toString(new Date(time))});
return after;
});
The result will then be:
const array2 = array1.concat(add);

Categories