How to merge properties inside object into one property? - javascript

I have object of orders
{
someUserData,
createdAt: 2019-11-05T18:32:25.199+00:00,
total: 5
}
I want to achieve this kind of data structure:
{
2019: {
0: 5,
1: 100
total: 999
}
}
2019 - year
0,1 etc. - months, total value to the right
total: yearly income
I've tried this:
calculateMonthlyRevenue = () => {
const { orders } = this.state;
const ordersMonthly = orders.map(x =>({
...x,
year: new Date(x.createdAt).getFullYear(),
month: new Date(x.createdAt).getMonth(),
}
));
const sumPerMonth = ordersMonthly.reduce((acc, cur) => {
acc[cur.year] = acc[cur.year] + cur.total || cur.total;
acc[cur.month] = acc[cur.month] + cur.total || cur.total;
return acc;
}, {})
};
acc is giving me
{
10: amount of all Novembers throught history,
2019: I get the total amount, that is good but the data structure is not
what I need.
}
I've tried this:
acc[cur.year][cur.month] = acc[cur.year][cur.month] + cur.total || cur.total;
and this
acc[cur.year[cur.month]] = acc[cur.year[cur.month]] + cur.total || cur.total;
And I still get stuck.
Upper line of codes gives me
9: amount
undefined: amount
The last line of code throws an error (Can not read property undefined of 10)

You could split the ISO 8601 date string for getting year and month and use a default object with total for the year and a default value of zero for the month.
Add to both targets the total from the original object.
var data = [{ someUserData: 'foo', createdAt: '2019-11-05T18:32:25.199+00:00', total: 5 }],
result = data.reduce((r, { createdAt, total }) => {
var [year, month] = createdAt.split('-', 2);
r[year] = r[year] || { total: 0 };
r[year][month -1 ] = (r[year][month - 1] || 0) + total;
r[year].total += total;
return r;
}, {});
console.log(result);

Related

Count dates within date intervals

I've an array abc containing date and time. I need to convert it into time slots of 1 day with limits determined by startDate and endDate with 'x' containing time slots and 'y' containing count of occurrence in those time slots. How can I get the count of occurrences in abc as per the interval and map it correctly it as per the date intervals?
const abc = ['2021-09-05T00:53:44.953Z', '2021-08-05T05:08:10.950Z', '2022-03-05T00:53:40.951Z'];
const startDate = '2021-07-05';
const endDate = '2021-11-05';
const res = [{x: '2021-07-05 - 2021-08-05' , y: '1' },{x: '2021-08-05 - 2021-09-05' , y: '2' }, {x: '2021-09-05 - 2021-10-05' , y: '1' },{x: '2021-10-05 - 2021-11-05' , y: '0' }];
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
As per my understanding, I created a simple working demo as per the start and end date you provided in the question :
const abc = ['2021-09-05T00:53:44.953Z', '2021-08-05T05:08:10.950Z', '2022-03-05T00:53:40.951Z'];
const startDate = '2021-07-05';
const endDate = '2021-11-05';
function countDates(inputArray, startDate, endDate) {
let count = 0;
const dateArray = abc.map((item) => new Date(item.split("T")[0]).getTime());
dateArray.forEach((dayTime) => {
if(dayTime >= new Date(startDate).getTime() && dayTime <= new Date(endDate).getTime()) {
count ++;
}
});
return [{x: `${startDate} - ${endDate}`, y: count}];
}
console.log(countDates(abc, startDate, endDate));
Note : I am assuming you have to fetch a range once at a time between startDate and endDate.
This may be one possible solution to achieve the desired objective:
Code Snippet
Please look at countWithinLimits method which houses the significant portions of the solution.
const data = [
'2021-07-05T00:53:44.953Z', '2021-07-04T00:53:44.953Z',
'2021-07-14T00:53:44.953Z', '2021-07-12T00:53:44.953Z',
'2021-07-06T00:53:44.953Z', '2021-07-05T00:53:44.953Z',
'2021-07-07T00:53:44.953Z', '2021-07-11T00:53:44.953Z',
'2021-07-08T00:53:44.953Z', '2021-07-10T00:53:44.953Z',
'2021-07-09T00:53:44.953Z', '2021-07-07T00:53:44.953Z',
'2021-07-10T00:53:44.953Z', '2021-07-05T00:53:44.953Z',
'2021-07-11T00:53:44.953Z', '2021-07-07T00:53:44.953Z',
];
const startDate = '2021-07-05';
const endDate = '2021-07-11';
// expected result structure for reference
const expectedResult = [
{x: '2021-07-05 - 2021-07-06', y: '1' },
{x: '2021-07-06 - 2021-07-07', y: '2' },
{x: '2021-07-07 - 2021-07-08', y: '1' },
{x: '2021-07-08 - 2021-07-09', y: '0' }
];
const countWithinLimits = (st, en, arr = data) => {
// helper function to add 'i' days to given 'dt'
const addDays = (dt, i) => {
const nx = new Date(dt);
return (
(
new Date(nx.setDate(nx.getDate() + i))
).toISOString().split('T')[0]
);
};
// transform 'dt' into look like 'x' in the expected result
const transformToKey = dt => (`${dt} - ${addDays(dt, 1)}`);
// set constants for start and end dates
const stDate = new Date(st), enDate = new Date(en);
// first determine the number of slots
// (each will be 1-day duration, from st till en)
const numDays = (
Math.ceil(
Math.abs(enDate - stDate) / (1000 * 60 * 60 * 24)
)
);
// next, obtain an array with the slots
// something like this: ['2021-07-05 - 2021-07-06', ....]
const slots = (
[...Array(numDays).keys()]
.map(i => addDays(st, i))
.map(d => transformToKey(d))
);
// generate an object with props as the slots and values as zeroes
// like this: { '2021-07-05 - 2021-07-06': 0, ....}
const slotObj = slots.reduce(
(fin, itm) => ({...fin, [itm]: 0}),
{}
);
// iterate through the data (arr)
// find the slot in which a given date fits
// and add 1 to the counter, if the slot is found in slotObj
// do not count the date if it doesn't match any slots
const countPerSlot = arr.reduce(
(fin, itm) => ({
...fin,
...(
[transformToKey(itm.split('T')[0])] in fin
? {
[transformToKey(itm.split('T')[0])]: (
fin[transformToKey(itm.split('T')[0])] + 1
)
}
: {}
)
}),
{...slotObj}
);
// finally, transform the countPerSlot object
// into the expected result array
return (
Object.entries(countPerSlot)
.map(
([k, v]) => ({ x: k, y: v})
)
);
};
console.log(countWithinLimits(startDate, endDate));
Explanation
While there are comments in-line in the above code-snippet, should there be any specific point that requires a more detailed explanation, 'comments' below may be used to notify and this answer may be updated with more details.
The big-picture idea is this:
split the solution into different smaller-parts
first, generate the time-slots (of length 1 day)
next, create an object where the props is the period (like 2021-07-05 - 2021-07-06)
now, iterate through the data and increment a counter corresponding to the prop where the date fits
and finally, transform the object into an array that matches the expected result ([ {x : '2021-07-05 - 2021-07-06', y: '2' }, .... ])

JavaScript array of dates to array of ranges of dates

I have a JavaScript array of dates (as strings) like the following:
["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"]
I want to convert this into an array of arrays of [first, last] contiguous date ranges, e.g., as below:
[["2020-07-24T04:00:00.000Z", "2020-08-01T04:00:00.000Z"], ["2020-11-29T05:00:00.000Z"], ["2020-12-30T05:00:00.000Z", "2021-01-02T05:00:00.000Z"], []]
How do I do this? Code attempt below:
var ranges = [];
for (var i = 0; i < popNull.length; i++) {
let currentRange = [];
let current = new Date(popNull[i]);
let tomorrow = new Date(current.getTime() + (24 * 60 * 60 * 1000));
let next = new Date(popNull[i+1]);
if (next === tomorrow) {
}
else {
}
}
I've made a couple of assumptions in the code below
That the dates are pre-sorted in ascending date order
That "contiguous" means less than or equal to 24 hours.
All dates are formatted in a way that can be passed directly to the Date constructor on the platform of choice.
const input = ["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"].map(x => new Date(x));
let aggregation = input.reduce( (acc,i) => {
if(acc.prev){
const diffInHrs = (i - acc.prev)/1000/60/60;
if(diffInHrs <= 24){
acc.result[acc.result.length-1][1] = i;
}
else{
acc.result.push([i])
}
acc.prev = i;
return acc;
}
else{
return {prev:i, result:[[i]]}
}
},{});
console.log(aggregation.result)
You can reduce the dates by keeoing track of the latest and checking the current with the previous. You can diff their epoch valyes and check if they are within a day.
const dates = ["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"];
const DAY_MILLIS = 8.64e7;
const ranges = dates
.reduce((acc, dateStr, index, all) => {
const dateObj = new Date(dateStr);
if (acc.length === 0) {
acc.push({ start: dateObj, prev: dateObj });
} else {
let last = acc[acc.length - 1];
const { start, prev } = last;
if (dateObj.getTime() - prev.getTime() <= DAY_MILLIS) {
last.prev = dateObj;
} else {
last.end = prev;
acc.push({ start: dateObj, prev: dateObj });
}
if (index === all.length - 1) {
last = acc[acc.length - 1];
if (last.end == null) {
last.end = last.prev;
}
}
}
return acc;
}, [])
.map(({ start, prev, end }) =>
((startStr, endStr) =>
startStr !== endStr ? [startStr, endStr] : [startStr])
(start.toISOString(), end.toISOString()));
console.log(ranges);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Output
[
[ "2020-07-24T04:00:00.000Z", "2020-08-01T04:00:00.000Z" ],
[ "2020-11-29T05:00:00.000Z" ],
[ "2020-12-30T05:00:00.000Z", "2021-01-02T05:00:00.000Z" ],
[ "2021-02-18T05:00:00.000Z" ]
]
You can do the following using Array#reduce():
Go through each date.
Check if the current date will extend last range.
if yes, then overwrite the end in the range pair (second element)
if no, start a new range
If it happens that a range only has a single date, then use the start to compare with. The logic still holds - extending the range will add a second date. If the new date is not within the desired time frame, then a new range is created and the previous range is left with a single element in it.
const areDatesWithin = ms => (str1, str2) => {
if (!str1 || !str2)
return false;
const date1 = new Date(str1);
const date2 = new Date(str2);
return (date2 - date1) <= ms;
}
const areDatesWithin1Day = areDatesWithin(1000 * 60 * 60 * 24);
function combineInRanges(dates) {
return dates.reduce((acc, nextDate) => {
const lastDateRange = acc[acc.length-1] ?? [];
//compare with range end (if there) or range start
const lastDate = lastDateRange[1] ?? lastDateRange[0];
//check if the range needs to be extended
const mergeWithRange = areDatesWithin1Day(lastDate, nextDate);
if (mergeWithRange) {
//change the end of the range
lastDateRange[1] = nextDate;
} else {
//start a new range
acc.push([nextDate]);
}
return acc;
}, []);
}
const arr = ["2020-07-24T04:00:00.000Z", "2020-07-25T04:00:00.000Z", "2020-07-26T04:00:00.000Z", "2020-07-27T04:00:00.000Z", "2020-07-28T04:00:00.000Z", "2020-07-29T04:00:00.000Z", "2020-07-30T04:00:00.000Z", "2020-07-31T04:00:00.000Z", "2020-08-01T04:00:00.000Z", "2020-11-29T05:00:00.000Z", "2020-12-30T05:00:00.000Z", "2020-12-31T05:00:00.000Z", "2021-01-01T05:00:00.000Z", "2021-01-02T05:00:00.000Z", "2021-02-18T05:00:00.000Z"];
console.log(combineInRanges(arr));
https://stackoverflow.com/a/67182108/20667780
Jamiec answer is working. If you have a date array with UTC dates correctly offsetted to local timezone, then the daylight save start/end date will have more than 24 hours. You have to change the diffInHrs to 25 instead of 24.
Otherwise, its a perfect answer.
It's a sort of reduction based on the even-ness of the index...
let array = ['a', 'b', 'c', 'd', 'e', 'f'];
let pairs = array.reduce((acc, el, idx) => {
idx % 2 ? acc[acc.length-1].push(el) : acc.push([el]);
return acc;
}, []);
console.log(pairs)

return item with closest time from now JavaScript / Moment.js

I am working on an application related to logs and times. I have this array with objects (logs). I would like to find the object with the checkin_time (which is a property from the object) closest to now. So If I have two objects, one with an checkin_time from "2018-04-05 08:04:12" and one with "2018-04-05 10:02:12" I would like to find the object with "2018-04-05 10:02:12" because that one is the closest time from now.
I tried something with the Moment.js library but that didn't worked out. I am using the Vue framework.
UPDATE
I've tried one of the answers below but I still got undefined back. Is there something I don't see?
Code
methods: {
getLog() {
this.users.forEach(element => {
element.logs.forEach((log) => {
this.Logs.push(log);
})
});
var unfinished = this.Logs.filter((log) => {
return log.finished == false;
});
console.log(unfinished);
const input = [
{id: 1, checkin_time: "2030-05-05 10:22:02"}, // 10 AM.
{id: 2, checkin_time: "2030-05-05 08:22:02"} // 8 AM.
]
console.log(input);
// Closest From Now.
const closestFromNow = times => times.filter(x => Date.now() < new Date(x.checkin_time)).sort((a, b) => new Date(a.checkin_time)*1 - new Date(b.checkin_time)*1)[0]
// Output.
const output = closestFromNow(unfinished)
const output2 = closestFromNow(input)
// Proof.
console.log(output) // Undefined
console.log(output2) // ID 2. 8 AM.
}
}
See Map, Math.min(), and Math.abs() for more info.
// Input.
const input = [
{id: 1, checkin_time: "2030-05-05 16:22:02"}, // 4 PM MAY 5 2030.
{id: 2, checkin_time: "2030-05-05 08:22:02"}, // 8 AM MAY 5 2030.
{id: 3, checkin_time: "2000-05-05 13:22:02"}, // 1 PM MAY 5 2030.
{id: 4, checkin_time: "2000-05-05 11:22:02"}, // 11 AM MAY 5 2030.
]
// Is Before Now
const isBeforeNow = x => (Date.now() > x)
// Generate Key.
const generateKey = x => Math.abs(Date.now()*1 - x*1)
// Closest From Now.
const closestFromNow = (times, restriction) => {
const m = new Map(times.map(x => {
let date = new Date(x.checkin_time)
if (restriction == 'before') {
if (isBeforeNow(date)) date = generateKey(date)
else date = undefined
}
else if (restriction == 'after') {
if (!isBeforeNow(date)) date = generateKey(date)
else date = undefined
}
else {
date = generateKey(date)
}
return [date, x]
}))
m.delete(undefined)
return m.get(Math.min(...m.keys()))
}
// Proof.
console.log('Closest Before Now', closestFromNow(input, 'before')) // ID 3.
console.log('Closest After Now', closestFromNow(input, 'after')) // ID 2.
console.log('Closest From Now In General 1', closestFromNow(input)) // ID 3.
console.log('Closet From Now In Generate 2', closestFromNow([...input, {id: 11, checkin_time: "2020-05-05 11:22:02"}])) // ID 11.
methods: {
getLog() {
var bigestElem = null;
var closestTime = 0;
var elemTime = 0;
this.users.forEach(element => {
element.logs.forEach((log) => {
elemTime = new Date(log.checkin_time).getTime()
if(log.finished === false && elemTime > closestTime){
closestTime = elemTime;
bigestElem = log;
}
this.Logs.push(log);
})
});
console.log(bigestElem);
return bigestElem
}
},
You can create a helper function as :
const input = [
{id: 1, checkin_time: "2030-05-05 10:22:02"}, // 10 AM.
{id: 2, checkin_time: "2030-05-05 08:22:02"} // 8 AM.
]
function findNearestTime(times){
let currentTime = Date.now();
let diff = times.map(time => {
return Math.abs(currentTime - Date.parse(time.checkin_time));
})
let i = diff.indexOf(Math.min(...diff));
return times[i].checkin_time;
}
let latest = findNearestTime(input);
alert("nearest time is :" + latest)
Here is the working fiddle
Reference: Date.now() and Date.parse()

How can I use a hashmap or map of an array to return the category with the highest total?

Here is my array.
donations = [
{
donateTo: "BaseCamp",
amount: 1000,
date: "12/19/2014, 08:40"
},
{
donateTo: "Where Most Needed",
amount: 3000,
date: "12/12/2014, 08:40"
},
{
donateTo: "Where Most Needed",
amount: 2000,
date: "12/11/2014, 08:40"
}
];
How can I return something like this? Where the donation with the donateTo that has the highest total donations is returned along with that total and the count of the gifts that made up that total.
{ donateTo: "Where Most Needed", total: 5000, count: 2}
I was previously able to get the results with MongoDB, but because I'm using Meteor, the aggregation is really ugly and not reactive. I'd rather fetch the cursor and then use a javascript function on the client side to get the data I need out.
Thanks
Here's an implementation using underscore:
var orgs = {};
_.each(donations, function(donation) {
if (orgs[donation.donateTo] == null)
orgs[donation.donateTo] = 0;
orgs[donation.donateTo] += donation.amount;
});
var amount = _.max(_.values(orgs));
var donateTo = _.invert(orgs)[amount];
var count = _.where(donations, {donateTo: donateTo}).length;
var result = {donateTo: donateTo, amount: amount, count: count};
console.log(result);
You can loop through the items and group them in an object, then loop through the properties in the object to find the largest amount:
var donations = [
{
donateTo: "BaseCamp",
amount: 1000,
date: "12/19/2014, 08:40"
},
{
donateTo: "Where Most Needed",
amount: 3000,
date: "12/12/2014, 08:40"
},
{
donateTo: "Where Most Needed",
amount: 2000,
date: "12/11/2014, 08:40"
}
];
var sums = {};
for (var i = 0; i < donations.length; i++) {
var donateTo = donations[i].donateTo;
if (sums.hasOwnProperty(donateTo)) {
sums[donateTo].amount += donations[i].amount;
sums[donateTo].count++;
} else {
sums[donateTo] = { donateTo: donateTo, amount: donations[i].amount, count: 1 };
}
}
var obj = null;
for (donateTo in sums) {
if (obj == null || sums[donateTo].amount > obj.amount) {
obj = sums[donateTo];
}
}
// show in Stackoverflow snippet
document.write(JSON.stringify(obj));
You can first iterate the documents to group them together by the donateTo field.
var m = {}; // to hold the grouped records by `donateTo`
donations.forEach(function(i){
if(!m[i["donateTo"]]){
m[i["donateTo"]] = {};
m[i["donateTo"]] = i;
m[i["donateTo"]]["count"] = 1;
}
else{
m[i["donateTo"]]["count"]++;
m[i["donateTo"]]["amount"] += i.amount;
}
});
And then find the group with the greatest amount:
var result = {amount:0}; // to hold the group with the largest amount
Object.keys(m).forEach(function(key){
if(m[key].amount > result.amount){
result = m[key];
}
})
delete result["date"];
console.log(result);
There is no super slick way to do this since you have to accumulate all the totals and then pick the highest one at the end and the very last entry in the array could completely change the highest value so you have to accumulate all the sub-totals as you go.
This function below accumulates a map of all the donateTo strings encountered and keeps a running total and cnt for each one. As it goes along, it then keeps track of which donateTo key has the highest total so far, saving an extra pass to compute the highest one.
function findHighestSum(list) {
// collect cumulative totals
var totals = {}, highestTotal = 0, highestKey;
list.forEach(function(item) {
var key = item.donateTo;
if (!totals[key]) {
totals[key] = {amount: item.amount, cnt: 1};
} else {
totals[key].amount += item.amount;
totals[key].cnt++;
}
if (totals[key].amount > highestTotal) {
highestTotal = totals[key].amount;
highestKey = key;
}
});
// { donateTo: "Where Most Needed", total: 5000, count: 2}
return {donateTo: highestKey, total: highestTotal, count: totals[highestKey].cnt};
}
Working demo: http://jsfiddle.net/jfriend00/7cfdsftz/
Because underscore is fun!
_.chain(donations)
.reduce(function(m, c) {
var findItem = _.findWhere(m, { 'donateTo': c.donateTo});
if (findItem) {
findItem.count++;
findItem.total += c.amount;
} else {
m.push({
'donateTo':c.donateTo,
'count':1,
'total':c.amount});
};
return m; }, [])
.max(function(k) { return k.total})
.value();
Using underscore...
// reduce donations, finally returning object with largest amount total
var highest = _.reduce(donations, function(memo, item, index){
// add to amount total if group exists, else init group
if(memo[item.donateTo]){
memo[item.donateTo].amount += item.amount;
memo[item.donateTo].count++;
} else {
memo[item.donateTo] = {
donateTo: item.donateTo,
amount:item.amount,
count:1
};
}
// if it is last iteration...
if(index === donations.length - 1){
// extract the max value
memo = _.max(_.toArray(memo), function(item){
return item.amount;
});
}
return memo;
}, {});
Using underscore js ...
// return the max (amount) of sorted, and collapsed array
var result = _.max( _.reduce( _.sortBy(donations, 'donateTo'), function(memo, item){
// if the last item has same key, update it (items are sorted by `donateTo`)
var _last = _.last(memo);
if(_last && _last.donateTo === item.donateTo){
_last.amount += item.amount;
_last.count++;
// otherwise create it
} else {
memo.push( _.extend( _.omit(item, 'date'), {'count':1} ) );
}
return memo
}, []), 'amount');
Underscore golf...
var h = {}, c={};
var result = _.max(donations, function(o){ var i = o.donateTo;
delete o.date; c[i] = ++c[i]||1; o.count=c[i];
return o.amount = h[i] = (h[i]||0)+o.amount
});

Counting array elements with specific date in javascript

I have an array of Date() objects in javascript and I want to count the number of events on each day.
Here is an example:
What I have is:
Array [ Date 2014-12-04T10:30:20.000Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z ]
What I want is:
Array [{date: '2014-12-04', counts: 1}, {date: '2014-12-05', counts: 3}]
Thanks a lot!
Max
Basic answer:
var arr = [], // fill it with array with your data
results = {}, rarr = [], i, date;
for (i=0; i<arr.length; i++) {
// get the date
date = [arr[i].getFullYear(),arr[i].getMonth(),arr[i].getDate()].join("-");
results[date] = results[date] || 0;
results[date]++;
}
// you can always convert it into an array of objects, if you must
for (i in results) {
if (results.hasOwnProperty(i)) {
rarr.push({date:i,counts:results[i]});
}
}
These can be made much easier with lodash functions, and Array.forEach() in ES5
You much better off having a simple object with the keys as the date and the value as the count. I've added a simple pad function that prefixes a zero where the number is a single digit as per your output requirements.
function pad(n) {
return n.toString().length == 1 ? '0' + n : n;
}
function getCount(arr) {
var obj = {};
for (var i = 0, l = arr.length; i < l; i++) {
var thisDate = arr[i];
var day = pad(thisDate.getDate());
var month = pad(thisDate.getMonth() + 1);
var year = thisDate.getFullYear();
var key = [year, day, month].join('-');
obj[key] = obj[key] || 0;
obj[key]++;
}
return obj;
}
getCount(arr); // Object { 2014-04-12: 1, 2014-05-12: 3 }
DEMO
I came across the same issue and found this solution which uses Map()
`
calc = (obj) => {
const orders = []
const dates_map = new Map()
//iterate through all the objects inside the orders array
orders.forEach(order => {
// format and get the date
const date = new Date(order.created_at).toLocaleDateString('en-GB')
//check if the date key exists in the Map() and save it in a temp
const temp = dates_map.get(date) || false
// if it does not exist
if (temp) {
// clone the object
const previous = {...temp}
// increase counter
previous.count += 1
dates_map.set(date, previous)
}else{
//create new object to avoid overwriting
const result = {}
result.count = 1
dates_map.set(date, result)
}
})
console.log(dates_map)
}
And this is the output
Output: Map(3) {
'08/05/2021' => { count: 2 },
'09/05/2021' => { count: 1 },
'11/05/2021' => { count: 2,}
}
`

Categories