So I have this array:
var period = [{"total":852, "date":"2016-03"}, {"total":963, "date":"2016-03"},{"total":789,"date":"2016-02"},{"total":456,"date":"2016-04"},{"total":123,"date":"2016-01"},{"total":723,"date":"2016-01"}];
I need to display "total" data grouped by month. Which means I have to sum "total" amount on months that are repeated on the array (2016-03, 2016-01). To find the solution I need to understand why this
for ( var i = 0; i < period.length; i++ ){
if (periodB.indexOf(period[i].date) == -1){
periodB.push(period[i].date);
}
Returns this:
["2016-03", "2016-02", "2016-04", "2016-01"]
While this:
for ( var i = 0; i < period.length; i++ ){
if (periodB.indexOf(period[i].date) == -1){
periodB.push({"date": period[i].date, "total": period[i].total});
}
}
Is returning this:
[{date: "2016-03",total: 1704}, {date: "2016-03", total: 1926}, {date:"2016-02", total: 1578},{date: "2016-04",total: 912}, {date: "2016-01",total: 246}, {date: "2016-01", total: 1446 }]
On the first case repeated "dates" are not being pushed on to periodB array, but then on the second case they are.
You can solve your task using temporary object and one forEach loop
var obj = {};
period.forEach(e => {
var month = e.date.split('-')[1]
obj[month] = obj[month] + e.total || e.total
});
Result will be an object with month as key and total sum as a value
{
'03': 1815,
'02': 789,
'04': 456,
'01': 846
}
Working example:
var period = [{ "total": 852, "date": "2016-03" }, { "total": 963, "date": "2016-03" }, { "total": 789, "date": "2016-02" }, { "total": 456, "date": "2016-04" }, { "total": 123, "date": "2016-01" }, { "total": 723, "date": "2016-01" }];
var obj = {};
period.forEach(e => {
var month = e.date.split('-')[1]
obj[month] = obj[month] + e.total || e.total
});
document.write(JSON.stringify(obj, 0, 2));
Related
I want to merge objects in array so that objects with the same id (which is a child object) can sum the total_price and total_quantity values.
Here is my data array:
var data = [
{
"_id": {
"month": 5,
"year": 2021
},
"total_price": 145111500,
"total_quantity": 7
},
{
"_id": {
"month": 6,
"year": 2021
},
"total_price": 98386000,
"total_quantity": 5
},
{
"_id": {
"month": 6,
"year": 2021
},
"total_price": 32500000,
"total_quantity": 3
}
]
I want to merge objects that have the duplicate "_id". Here is the output result:
var merge = [
{
"_id": {
"month": 5,
"year": 2021
},
"total_price": 145111500,
"total_quantity": 7
},
{
"_id": {
"month": 6,
"year": 2021
},
"total_price": 130886000,
"total_quantity": 8
}
]
Thanks in advance.
const data = [
{ "_id": { "month": 5, "year": 2021 }, "total_price": 145111500, "total_quantity": 7 },
{ "_id": { "month": 6, "year": 2021 }, "total_price": 98386000, "total_quantity": 5 },
{ "_id": { "month": 6, "year": 2021 }, "total_price": 32500000, "total_quantity": 3 }
];
const res = [...
// iterate over the list
data.reduce((map, item) => {
// construct key from _id
const key = `${item._id.month}-${item._id.year}`;
// get prev map value of key if exists
const prev = map.get(key);
// update map, if prev not found, set value as item, or update it with the added values
map.set(
key,
!prev
? item
: { ...item, total_price: prev.total_price + item.total_price, total_quantity: prev.total_quantity + item.total_quantity }
);
return map;
}, new Map)
// return map values
.values()
];
console.log(res);
var ids = [];
var merge = [];
for (let i = 0; i < data.length; i++) {
obj = data[i];
let dupId = false;
for (let j = 0; j < ids.length; j++) {
if (ids[j]["month"] == obj["_id"]["month"] && ids[j]["year"] == obj["_id"]["year"]) {
merge[j]["total_price"] += obj["total_price"];
merge[j]["total_quantity"] += obj["total_quantity"];
dupId = true;
break;
}
}
if (!dupId) {
ids.push(obj["_id"]);
merge.push(obj);
}
}
The code will:
Declare and initialize merge array to an empty array
Loop through all elements from data array
And inside, check for duplicate of element in merge array
If found, add total quantities and total prices
If not found, add element to merge array
I have an array that has a object with two properties, 'location' and 'needs'. The needs property has an array of objects with a date and count {date: "2021-06-15", count: 10} so an array would look like this:
{
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
}
What I need to do is to use Momentjs to use today's date, figure out the two week period starting from today, and then map the needs-count to the date in the moment loop. If there is a date missing (like in the example below), it should put a 0 as the count
A final array would look like...
{
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56 // this had a count in the initial object
},
{
"date": "2021-04-07",
"count": 0
},
{
"date": "2021-04-08",
"count": 0
},
{
"date": "2021-04-09",
"count": 0
},
{
"date": "2021-04-10",
"count": 0
},
{
"date": "2021-04-11",
"count": 0
},
{
"date": "2021-04-12",
"count": 0
},
{
"date": "2021-04-13",
"count": 10 // this had a count in the initial object
},
...
...
...
]
}
In terms of a function, the closest I have got is
let startDay = moment().format('YYYY-MM-DD');
let endDay = moment().add(14, 'days').format('YYYY-MM-DD');
let startDate = moment(startDay);
let endDate = moment(endDay);
let datesBetween = [];
let startingMoment = startDate;
while(startingMoment <= endDate) {
for (let count = 0; count < 15; count ++) {
// at this point im trying to take 'week' which has the location property and needs property and trying to merge them together... but failed miserably.
if (week.needs[count].date === startingMoment) {
datesBetween.push([startingMoment.clone(), week.needs[count].count]);// clone to add new object
startingMoment.add(1, 'days');
} else {
datesBetween.push([startingMoment.clone(), 0]);// clone to add new object
}
}
}
Can someone see where I went so wrong?
const week = {
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
}
let current = moment();
const allDates = [];
const FORMAT = 'YYYY-MM-DD';
for (let count = 0; count < 14; count++) {
const found = week.needs.find(i => i.date === current.format(FORMAT));
if (found) {
allDates.push(found);
} else {
allDates.push({
date: current.format(FORMAT),
count: 0,
});
}
current.add(1, 'day');
}
week.needs = allDates;
console.log(week);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous"></script>
You could do something like this :
let dates = {
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
};
let day = moment();
for( let i=0; i< 15; i++){
let date = day.add(1, "days").format("YYYY-MM-DD");
console.log(`Looking if ${date} is in array...`)
if(dates.needs.find(obj => obj.date === date)) continue;
console.log(`Adding ${date}`)
dates.needs.push({ date, count : 0 })
}
dates.needs.sort( (a,b) => a.date > b.date ? 1: -1 );
console.log(dates)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
I have this variable named: var quantity.
This variable changes continuously. For example: quantity = 1, quantity = 26...
On the other hand I have an array of elements with prices according to the quantity of the product: var quantity_prices.
var quantity_prices = [
{
"quantity": 1,
"price_pvp": 7.96
}, {
"quantity": 5,
"price_pvp": 7.96
}, {
"quantity": 15,
"price_pvp": 6.97
}, {
"quantity": 25,
"price_pvp": 5.97
}
];
I want to make that if quantity is between quantities 1 and 5, 6 and 14, 15 and 24, the product has the right price.
Example:
if the quantity is 16, the price I want to take is: 5,95€.
I've thought about using a for loop but I don't know how to continue to make this work what I want to do:
for (var i = 0; i < this.quantity_prices.length; i++) { // if quantity is between 1 and 5
new_price = this.quantity_prices[i].price_pvp;
// elseif quantity is between 6 and 14
new_price = this.quantity_prices[i].price_pvp;
// elseif quantity is between 15 and 24
new_price = this.quantity_prices[i].price_pvp;
}
var quantity_prices = [
{
"quantity": 1,
"price_pvp": 7.96,
},
{
"quantity": 5,
"price_pvp": 7.96,
},
{
"quantity": 15,
"price_pvp": 6.97,
},
{
"quantity": 25,
"price_pvp": 5.97,
}
];
for(let i=0;i<quantity_prices.length;i++){
if(quantity_prices[i].quantity>0 && quantity_prices[i].quantity<5 )
{
//whatever the required output you want.
quantity_prices[i].new_price=quantity_prices[i].price_pvp;
}if(quantity_prices[i].quantity>6 && quantity_prices[i].quantity<14){
}
if(quantity_prices[i].quantity>15 && quantity_prices[i].quantity<24){
}
}
console.log(quantity_prices)
Here try it with this:
function check(){
this.quantity_prices.find(({price}) => {
if(price_pvp > 1 && price_pvp < 5){
// do something
}
if(price_pvp > 6 && price_pvp < 14){
// do something
}
if(price_pvp > 15 && price_pvp < 24){
// do something
}
}
}
You can group according to your req as per below code and then print the price.
var quantity_prices = [{
"quantity": 1,
"price_pvp": 7.96,
},
{
"quantity": 5,
"price_pvp": 7.96,
},
{
"quantity": 15,
"price_pvp": 6.97,
},
{
"quantity": 25,
"price_pvp": 5.97,
}
];
var group1_5 = quantity_prices.filter(q => q.quantity >= 1 && q.quantity <= 5);
console.log(group1_5);
//print your price
if (group1_5.length > 0) {
console.log(group1_5[0].price_pvp)
}
var group6_16 = quantity_prices.filter(q => q.quantity >= 6 && q.quantity <= 14);
console.log(group6_16);
You can search for the right quantity, then return the price for this amount.
I'm assuming that if the quantity is not found directly we'll return the next entry in the quantity / price table.
const quantity_prices = [ { "quantity": 1, "price_pvp": 7.96, }, { "quantity": 5, "price_pvp": 7.96, }, { "quantity": 15, "price_pvp": 6.97, }, { "quantity": 25, "price_pvp": 5.97, } ];
function getPrice(quantity, priceLookup) {
let entry = priceLookup.find((e,index) => e.quantity >= quantity || index === priceLookup.length-1);
return entry.price_pvp;
}
console.log("Price table:");
const quantities = [1,4,5,10,15,16,25,26,30];
for(let quantity of quantities ) {
console.log(`Price (${quantity }): €${getPrice(quantity, quantity_prices)}`);
}
I have some data by the hour and summarise/consolidate the array.
However, there are some hours which are blank in data.Items hence my array would skip the data point completely.
Is there a way where I can through my data/array and fill in the gaps and assign a '0' next to it?
for(i=0; i<dataLength; i++){
var date = new Date(data[i].ctimestamp);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
var date = moment(date).tz("Pacific/Auckland").format("DD/MM/YY HH:mm");
dateArray.push({"date" : date});
}
Here is an example - "11/12/18 05:00" and "11/12/18 06:00" are missing so it's skipped completely.
[{
"date": "11/12/18 08:00",
"count": 5
},
{
"date": "11/12/18 07:00",
"count": 4
},
{
"date": "11/12/18 04:00",
"count": 6
}]
Ideally, I would like it to show:
[
{
"date": "11/12/18 08:00",
"count": 5
},
{
"date": "11/12/18 07:00",
"count": 4
},
{
"date": "11/12/18 06:00",
"count": 0
},
{
"date": "11/12/18 05:00",
"count": 0
},
{
"date": "11/12/18 04:00",
"count": 6
}]
I think this simplifies the logic and produces the result you want:
const data = [
{
"date": "11/12/18 08:00",
"count": 5
},
{
"date": "11/12/18 07:00",
"count": 4
},
{
"date": "11/12/18 04:00",
"count": 6
}
];
let min = Number.MAX_VALUE;
let max = 0;
const dates = data.reduce((memo, {date, count}) => {
const time = new Date(date).getTime();
min = Math.min(min, time);
max = Math.max(max, time);
memo[time] = count;
return memo;
}, {});
const ONE_HOUR = 60 * 60 * 1000;
const dataOutput = [];
for (let i = min;i <= max;i += ONE_HOUR) {
dataOutput.push({
date: new Date(i).toLocaleString(),
count: dates[i] || 0
});
}
console.log(dataOutput)
I'll assume the array you posted as sample data, is called dataItems. Also, I'll use moment to handle time, but you can convert it to vanilla JS if you want.
So, what I would do is go through dataItems, and check if prev value is 1 hour prev to this value, if its not, add a new input.
dataItems.reduce((acc, val) => {
if(!acc) {
return [moment(val)];
}
let momentVal = moment(val)
if (momentVal.diff(acc[acc.length - 1], 'hours') !== 1){
acc.push(momentVal)
return acc;
} else {
while(momentVal.diff(acc[acc.length - 1], 'hours') !== 1){
acc.push(moment(acc[acc.length - 1]).add(1, 'hours')) //clone and add 1 hour
}
}
}])
I didn't take in consideration your object isn't just date, but that should be simple to adapt. The general logic is: go through your array, if the previous one is 1 hour less than right now, keep it going. Else, add a new input until the actual one is 1 hour after the last one on the array
I have an array of dates containing a count value. e.g.
[
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
},
{
"date": "2014-11-13T08:00:00.000Z",
"count": 4
}
{
"date": "2014-11-16T08:00:00.000Z",
"count": 4
}
]
How do I fill in the missing dates with count = 0, to produce the following in javascript:
[
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
},
{
"date": "2014-11-12T08:00:00.000Z",
"count": 0
},
{
"date": "2014-11-13T08:00:00.000Z",
"count": 4
},
...
]
as you appear to be using momentjs
the first thing that came to mind was use the moment().add(number, units) and moment().diff(input, units, asFloat)
something like
var data = [
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
}, {
"date": "2014-11-16T08:00:00.000Z",
"count": 4
}
];
var startDate = moment(data[0].date);
var endDate = moment(data[1].date);
var days = endDate.diff(startDate, 'd', false);
alert(days);
for (var i = 1; i < days; i++) {
data.splice(i,0, {"date" : startDate.add(1, 'd').toISOString(), 'count': 0 })
}
for (var i = 0; i < data.length; i++) {
alert(data[i].date);
}
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
Try this:
var arr = [
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
},
{
"date": "2014-11-16T08:00:00.000Z",
"count": 4
}
];
function fillDates(start, end) {
var output = [start];
var date = new Date(start.date);
var endDate = new Date(end.date);
do {
output.push({
"date": date.toISOString(),
"count": 0
});
date = new Date(date.getTime());
date.setDate(date.getDate() + 1);
} while (date < endDate);
output.push(end);
return output;
}
var start = arr[0];
var end = arr[1];
fillDates(start, end);
const models = [
{
date: '2018-10-17',
value: 3,
},
{
date: '2018-10-20',
value: 4,
},
{
date: '2018-10-21',
value: 5,
},
{
date: '2018-10-27',
value: 6,
},
];
const filledInDates = models.reduce((newArray, currentModel, index, originalArray) => {
const nextModel = originalArray[index + 1];
if (nextModel) {
const currentDate = moment(currentModel.date);
const daysBetween = moment(nextModel.date).diff(currentDate, 'days');
const fillerDates = Array.from({length: daysBetween - 1}, (value, dayIndex) => {
return {
value: currentModel.value,
date: moment(currentDate).add(dayIndex + 1, 'days').format('YYYY-MM-DD'),
};
});
newArray.push(currentModel, ...fillerDates);
} else {
newArray.push(currentModel);
}
return newArray;
}, []);
console.log(filledInDates);
Output:
[
{value:3, date:"2018-10-17"},
{value:3, date:"2018-10-18"},
{value:3, date:"2018-10-19"},
{value:4, date:"2018-10-20"},
{value:5, date:"2018-10-21"},
{value:5, date:"2018-10-22"},
{value:5, date:"2018-10-23"},
{value:5, date:"2018-10-24"},
{value:5, date:"2018-10-25"},
{value:5, date:"2018-10-26"},
{value:6, date:"2018-10-27"}
]