auto calculate total sum based on discount amounts - javascript

I'm doing some calculations of the total cost of items in an array that would be displayed in the HTML, the total sum should be such that when making the calculations, it should consider the discount amount against each row and add up together before it sums up all the rows total to make the total sum.
data
costItems = [
{
name: 'Corn Flakes'
unitPrice: 9,
quantity: 10,
hasDiscount: false,
discountPercentage: 10
},
{
name: 'Sugar'
unitPrice: 5,
quantity: 10,
hasDiscount: true,
discountPercentage: 10
},
{
name: 'Bread'
unitPrice: 2,
quantity: 7,
hasDiscount: false,
discountPercentage: 0
},
{
name: 'Salt'
unitPrice: 1,
quantity: 4,
hasDiscount: false,
discountPercentage: 0
}
]
Current Code I have
calculateTotalSum() {
this.totalSum = this.costItems.reduce((sum, {unitPrice, quantity}) => sum += unitPrice * quantity, 0);
console.log(this.totalSum)
}
This works by calculating the total sum ignoring the discount amounts but what I want to do is to consider the discounts in there

const costItems = [
{
name: 'Corn Flakes',
unitPrice: 9,
quantity: 10,
hasDiscount: false,
discountPercentage: 10,
},
{
name: 'Sugar',
unitPrice: 5,
quantity: 10,
hasDiscount: true,
discountPercentage: 10,
},
{
name: 'Bread',
unitPrice: 2,
quantity: 7,
hasDiscount: false,
discountPercentage: 0,
},
{
name: 'Salt',
unitPrice: 1,
quantity: 4,
hasDiscount: false,
discountPercentage: 0,
},
];
const totalSum = costItems.reduce(
(sum, { unitPrice, quantity, discountPercentage }) =>
(sum += unitPrice * quantity * (1 - discountPercentage / 100)),
0,
);
console.log(totalSum);

You can use Array.prototype.reduce.
let costItems = [{
name: 'Corn Flakes',
unitPrice: 9,
quantity: 10,
hasDiscount: false,
discountPercentage: 10
},
{
name: 'Sugar',
unitPrice: 5,
quantity: 10,
hasDiscount: true,
discountPercentage: 10
},
{
name: 'Bread',
unitPrice: 2,
quantity: 7,
hasDiscount: false,
discountPercentage: 0
},
{
name: 'Salt',
unitPrice: 1,
quantity: 4,
hasDiscount: false,
discountPercentage: 0
}
];
let sum = costItems.reduce((acc, val) => acc += (val.quantity * val.unitPrice) * ((100 - val.discountPercentage) / 100), 0);
console.log(sum)

Related

For loop accessing an array of objects with array's

const bankAccounts = [
{
id: 1,
name: "Susan",
balance: 100.32,
deposits: [150, 30, 221],
withdrawals: [110, 70.68, 120],
},
{ id: 2, name: "Morgan", balance: 1100.0, deposits: [1100] },
{
id: 3,
name: "Joshua",
balance: 18456.57,
deposits: [4000, 5000, 6000, 9200, 256.57],
withdrawals: [1500, 1400, 1500, 1500],
},
{ id: 4, name: "Candy", balance: 0.0 },
{ id: 5, name: "Phil", balance: 18, deposits: [100, 18], withdrawals: [100] },
];
function getAllWithdrawals(bankAccounts) {
let newArr = [];
for (let acc of bankAccounts) {
if (acc.withdrawals) {
newArr.push(acc.withdrawals)
} else if (!acc.withdrawals) {
newArr.push(0);
}
}
return newArr;
}
I am getting access to the array objects. But how do I get into the objects with the array of withdrawals with varying amounts, add them all and print that in the blank array "newArr"? Do I need another for loop? My overall goal is to iterate through the objects check which ones pass that have withdrawals array. If they do not have a withdrawals array I pass 0. The objects that do have withdrawals I need to iterate through those and add them up and push the total of the withdrawal array into the "newArr".
Here is a functional programming solution that uses map reduce:
const bankAccounts = [ { id: 1, name: "Susan", balance: 100.32, deposits: [150, 30, 221], withdrawals: [110, 70.68, 120], }, { id: 2, name: "Morgan", balance: 1100.0, deposits: [1100] }, { id: 3, name: "Joshua", balance: 18456.57, deposits: [4000, 5000, 6000, 9200, 256.57], withdrawals: [1500, 1400, 1500, 1500], }, { id: 4, name: "Candy", balance: 0.0 }, { id: 5, name: "Phil", balance: 18, deposits: [100, 18], withdrawals: [100] }, ];
function getAllWithdrawals(bankAccounts) {
return bankAccounts.map(obj => {
return obj.withdrawals ? obj.withdrawals.reduce((sum, num) => sum + num, 0) : 0;
});
}
console.log(getAllWithdrawals(bankAccounts));
Output:
[
300.68,
0,
5900,
0,
100
]
Docs:
Intro to map reduce: https://medium.com/poka-techblog/simplify-your-javascript-use-map-reduce-and-filter-bd02c593cc2d
.map(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
.reduce(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reduce
Here is an enhanced version where you pass the deposits or withdrawls key into the function:
const bankAccounts = [ { id: 1, name: "Susan", balance: 100.32, deposits: [150, 30, 221], withdrawals: [110, 70.68, 120], }, { id: 2, name: "Morgan", balance: 1100.0, deposits: [1100] }, { id: 3, name: "Joshua", balance: 18456.57, deposits: [4000, 5000, 6000, 9200, 256.57], withdrawals: [1500, 1400, 1500, 1500], }, { id: 4, name: "Candy", balance: 0.0 }, { id: 5, name: "Phil", balance: 18, deposits: [100, 18], withdrawals: [100] }, ];
function getSums(bankAccounts, key) {
return bankAccounts.map(obj => {
return obj[key] ? obj[key].reduce((sum, num) => sum + num, 0) : 0;
});
}
console.log({
deposits: getSums(bankAccounts, 'deposits'),
withdrawals: getSums(bankAccounts, 'withdrawals'),
});
Output:
{
"deposits": [
401,
1100,
24456.57,
0,
118
],
"withdrawals": [
300.68,
0,
5900,
0,
100
]
}
UPDATE 1: Based on request to use only for loops:
const bankAccounts = [ { id: 1, name: "Susan", balance: 100.32, deposits: [150, 30, 221], withdrawals: [110, 70.68, 120], }, { id: 2, name: "Morgan", balance: 1100.0, deposits: [1100] }, { id: 3, name: "Joshua", balance: 18456.57, deposits: [4000, 5000, 6000, 9200, 256.57], withdrawals: [1500, 1400, 1500, 1500], }, { id: 4, name: "Candy", balance: 0.0 }, { id: 5, name: "Phil", balance: 18, deposits: [100, 18], withdrawals: [100] }, ];
function getAllWithdrawals(bankAccounts) {
let result = [];
for (let obj of bankAccounts) {
let sum = 0;
if(obj.withdrawals) {
for (num of obj.withdrawals) {
sum += num;
}
}
result.push(sum);
}
return result;
}
console.log(getAllWithdrawals(bankAccounts));
Not sure if I understood your question, but if u have to sum ALL of the withdrawals you should do it in this way:
const bankAccounts = [
{
id: 1,
name: "Susan",
balance: 100.32,
deposits: [150, 30, 221],
withdrawals: [110, 70.68, 120],
},
{ id: 2, name: "Morgan", balance: 1100.0, deposits: [1100] },
{
id: 3,
name: "Joshua",
balance: 18456.57,
deposits: [4000, 5000, 6000, 9200, 256.57],
withdrawals: [1500, 1400, 1500, 1500],
},
{ id: 4, name: "Candy", balance: 0.0 },
{ id: 5, name: "Phil", balance: 18, deposits: [100, 18], withdrawals: [100] },
];
function getAllWithdrawals(bankAccounts) {
let newArr = [];
for (let acc of bankAccounts) {
if (!!acc.withdrawals) {
acc.withdrawals.forEach(withdrawal => newArr.push(withdrawal))
}
}
return newArr.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
}
console.log(getAllWithdrawals(bankAccounts))
Otherwise if you have to sum the withdrawals of the single object you have to use this code:
const bankAccounts = [
{
id: 1,
name: "Susan",
balance: 100.32,
deposits: [150, 30, 221],
withdrawals: [110, 70.68, 120],
},
{ id: 2, name: "Morgan", balance: 1100.0, deposits: [1100] },
{
id: 3,
name: "Joshua",
balance: 18456.57,
deposits: [4000, 5000, 6000, 9200, 256.57],
withdrawals: [1500, 1400, 1500, 1500],
},
{ id: 4, name: "Candy", balance: 0.0 },
{ id: 5, name: "Phil", balance: 18, deposits: [100, 18], withdrawals: [100] },
];
function getAllWithdrawals(bankAccounts) {
let newArr = [];
for (let acc of bankAccounts) {
if (!!acc.withdrawals) {
newArr.push(acc.withdrawals.reduce((accumulator, currentValue) => accumulator + currentValue, 0))
}
}
return newArr;
}
console.log(getAllWithdrawals(bankAccounts))

adding values in array where id's are the same

(14) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {itemId: 'F4', itemRate: 20, Amount: 20, itemName: 'Kesar pista', itemQuantity: 1}
1: {itemName: 'Vegetable manchuri', itemRate: 60, itemId: 'G5', Amount: 120, itemQuantity: 2}
2: {itemRate: 50, Amount: 50, itemQuantity: 1, itemId: 'C10', itemName: 'Dry fruit '}
3: {itemId: 'C3', itemRate: 40, itemQuantity: 1, Amount: 40, itemName: 'Butter scotch'}
4: {itemName: 'Panner sandwich + milk shake', Amount: 90, itemId: 'CS4', itemRate: 90, itemQuantity: 1}
5: {itemQuantity: 1, itemId: 'B5', itemRate: 70, Amount: 70, itemName: 'Panner burger'}
6: {itemId: 'C10', itemQuantity: 1, Amount: 50, itemName: 'Dry fruit ', itemRate: 50}
7: {itemQuantity: 2, itemName: 'American nuts', Amount: 100, itemRate: 50, itemId: 'C8'}
8: {itemName: 'Mango ', Amount: 50, itemQuantity: 1, itemId: 'C7', itemRate: 50}
9: {Amount: 40, itemId: 'C6', itemQuantity: 1, itemName: 'Choclate ', itemRate: 40}
10: {itemRate: 40, itemId: 'C3', itemQuantity: 1, Amount: 40, itemName: 'Butter scotch'}
11: {itemRate: 45, itemId: 'B1', itemName: 'Veg burger', Amount: 45, itemQuantity: 1}
12: {itemName: 'Veg cheese', Amount: 55, itemId: 'B2', itemQuantity: 1, itemRate: 55}
13: {itemName: 'Vanila', itemQuantity: 1, itemId: 'C1', Amount: 30, itemRate: 30}
length: 14
[[Prototype]]: Array(0)
I have a array. In the array there are 2 [id] values that are the same. I want to add the quantity,rate of these elements and merge the elements where the [id] are the same using javascript. I had tried following method but it shows wrong value.
let result = Object.values(this.orderDetail.reduce((c, {itemId,itemRate,itemQuantity,itemName}) => {
c[itemId] = c[itemId] || {itemId,itemRate,itemQuantity,itemName: 0};
c[itemId].itemRate += itemRate;
c[itemId].itemQuantity += itemQuantity;
c[itemId].itemName = itemName;
return c;
}, {}));
result
The issue is with the first line in the accumulator.
c[itemId] = c[itemId] || {itemId,itemRate,itemQuantity,itemName: 0};
You should assign the initial values here. This should be as below
c[itemId] = c[itemId] || { itemId, itemRate: 0, itemQuantity: 0, itemName: '', Amount: 0 };
Or else, you will be adding the first value twice to the accumulator.
Working Fiddle
const data = [{ itemId: 'F4', itemRate: 20, Amount: 20, itemName: 'Kesar pista', itemQuantity: 1 },
{ itemId: 'G5', itemName: 'Vegetable manchuri', itemRate: 60, Amount: 120, itemQuantity: 2 },
{ itemId: 'C10', itemRate: 50, Amount: 50, itemQuantity: 1, itemName: 'Dry fruit ' },
{ itemId: 'C3', itemRate: 40, itemQuantity: 1, Amount: 40, itemName: 'Butter scotch' },
{ itemId: 'CS4', itemName: 'Panner sandwich + milk shake', Amount: 90, itemRate: 90, itemQuantity: 1 },
{ itemId: 'B5', itemQuantity: 1, itemRate: 70, Amount: 70, itemName: 'Panner burger' },
{ itemId: 'C10', itemQuantity: 1, Amount: 50, itemName: 'Dry fruit ', itemRate: 50 },
{ itemId: 'C8', itemQuantity: 2, itemName: 'American nuts', Amount: 100, itemRate: 50 },
{ itemId: 'C7', itemName: 'Mango ', Amount: 50, itemQuantity: 1, itemRate: 50 },
{ itemId: 'C6', Amount: 40, itemQuantity: 1, itemName: 'Choclate ', itemRate: 40 },
{ itemId: 'C3', itemRate: 40, itemQuantity: 1, Amount: 40, itemName: 'Butter scotch' },
{ itemId: 'B1', itemRate: 45, itemName: 'Veg burger', Amount: 45, itemQuantity: 1 },
{ itemId: 'B2', itemName: 'Veg cheese', Amount: 55, itemQuantity: 1, itemRate: 55 },
{ itemId: 'C1', itemName: 'Vanila', itemQuantity: 1, Amount: 30, itemRate: 30 },
];
let result = Object.values(data.reduce((c, { itemId, itemRate, itemQuantity, itemName, Amount }) => {
const temp = { itemId, itemRate: 0, itemQuantity: 0, itemName: '', Amount: 0 };
c[itemId] = c[itemId] || temp;
c[itemId].itemRate += itemRate;
c[itemId].itemQuantity += itemQuantity;
c[itemId].itemName = itemName;
c[itemId].Amount += Amount;
return c;
}, {}));
console.log(result);
As I looked into the result, there is one extra time all values are passing into it. I guess you should try passing default values zero or an empty string to it.

Javascript sort array by date and alphabetical order

I want it to be sorted by date and alphabet in one sort how can i do that ?
I think alphabetical order works good but date not works properly. Thanks for answers.
Data structure :
[{
productId: 21,
title: "Huawei P40 Lite ",
brand: "Huawei",
price: 120,
discountPercentage: 10,
color: "Black",
createdDate: "2021-01-15T01:00:00+03:00",
},
{
productId: 22,
title: "Huawei P40 Lite",
brand: "Huawei",
price: 1026,
discountPercentage: 0,
color: "Green",
createdDate: "2021-01-16T01:00:00+03:00",
},
{
productId: 23,
title: "Apple iPhone 11",
brand: "Apple",
price: 1220,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-17T01:00:00+03:00",
},
{
productId: 24,
title: "Apple iPhone 12",
brand: "Apple",
price: 1420,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-18T01:00:00+03:00",
}],
Here my work :
jsfiddle.net/pazyqb01/
And tried different solutions for sort date somehow i couldn't make it work.
Sorted Array shoul be like above :
{
productId: 24,
title: "Apple iPhone 12",
brand: "Apple",
price: 1420,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-18T01:00:00+03:00",
},
{
productId: 23,
title: "Apple iPhone 11",
brand: "Apple",
price: 1220,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-17T01:00:00+03:00",
},
{
productId: 22,
title: "Huawei P40 Lite",
brand: "Huawei",
price: 1026,
discountPercentage: 0,
color: "Green",
createdDate: "2021-01-16T01:00:00+03:00",
},
{
productId: 21,
title: "Huawei P40 Lite ",
brand: "Huawei",
price: 120,
discountPercentage: 10,
color: "Black",
createdDate: "2021-01-15T01:00:00+03:00",
},
this way:
simply follow the list of your sorting criteria
const data =
[ { productId: 21, title: 'Huawei P40 Lite ', brand: 'Huawei', price: 120, discountPercentage: 10, color: 'Black', createdDate: '2021-01-15T01:00:00+03:00' }
, { productId: 22, title: 'Huawei P40 Lite', brand: 'Huawei', price: 1026, discountPercentage: 0, color: 'Green', createdDate: '2021-01-16T01:00:00+03:00' }
, { productId: 23, title: 'Apple iPhone 11', brand: 'Apple', price: 1220, discountPercentage: 11, color: 'White', createdDate: '2021-01-17T01:00:00+03:00' }
, { productId: 24, title: 'Apple iPhone 12', brand: 'Apple', price: 1420, discountPercentage: 11, color: 'White', createdDate: '2021-01-18T01:00:00+03:00' }
]
const fSort = (a,b) =>
{
let Dx = new Date(b.createdDate) - new Date(a.createdDate) // 1st criteria
if (Dx===0) Dx = a.title.trim().localeCompare(b.title.trim()) // 2nd
// if (Dx===0) Dx = ... // 3rd
// if (Dx===0) Dx = ... // 4th....
return Dx
}
console.log( data.sort(fSort))

How to select random object from JSON file in discord.js

I've done some searching around and I found some posts on here but my code doesn't want to work.
Basically I'm making a discord bot and I want to select an object from a JSON file at random.
This is my command:
const UserData = require('../data/users.js');
const monster = require('../data/monsters.json');
module.exports = {
name: 'battle',
aliases: ['fight'],
cooldown: 0,
description: 'User fights against a monster alone or in group',
execute(client, message, args) {
let enemy = monster[Math.floor(Math.random() * monster.length)]
UserData.findOne({
userID: message.author.id
}, (error, userdata) => {
if (error) console.log(error);
if (!userdata) {
return message.reply(`you don't have an account!`);
} else {
console.log(enemy);
return message.channel.send(`${enemy} spawned!`);
}
})
}
}
And this is my JSON file:
"1" : {
"name": "Blue Slime",
"hp": 20,
"atk": 12,
"def": 10,
"spatk": 3,
"spdef": 12,
"spd": 100,
"gold": 10,
"xp": 50,
"lvl": 1
},
"2": {
"name": "Red slime",
"hp": 20,
"atk": 12,
"def": 10,
"spatk": 3,
"spdef": 12,
"spd": 100,
"gold": 10,
"xp": 50,
"lvl": 1
},
"3": {
"name": "Green slime",
"hp": 20,
"atk": 12,
"def": 10,
"spatk": 3,
"spdef": 12,
"spd": 100,
"gold": 10,
"xp": 50,
"lvl": 1
}
}
If I want put the objects in the command manually and then randomly select them it works and if instead of "monster.length" I put a number then it also works but I still get undefined if it should be 3.
This way I also always get undefined in console log from monster.length.
What am I doing wrong?
Your monsters.json file contains an object and objects don't have lengths. You can however convert it to an array, using Object.values() that returns an array of the given object's own enumerable property values.
Check out the snippet below:
let monsters = {
1: {
name: 'Blue Slime',
hp: 20,
atk: 12,
def: 10,
spatk: 3,
spdef: 12,
spd: 100,
gold: 10,
xp: 50,
lvl: 1,
},
2: {
name: 'Red slime',
hp: 20,
atk: 12,
def: 10,
spatk: 3,
spdef: 12,
spd: 100,
gold: 10,
xp: 50,
lvl: 1,
},
3: {
name: 'Green slime',
hp: 20,
atk: 12,
def: 10,
spatk: 3,
spdef: 12,
spd: 100,
gold: 10,
xp: 50,
lvl: 1,
},
};
function randomObject(obj) {
let arr = Object.values(obj);
return arr[Math.floor(Math.random() * arr.length)];
}
let enemy = randomObject(monsters);
console.log(enemy);

javascript populate nested object from other nested object

I am rather new to JavaScript and I am following different tutorials at the moment. For visualisation of a d3js graph I like to restructure a small dataset so that the d3.layout.stack() function can deal with the data.
The original dataset looks as follows. Its an array of objects:
var dats = [{ apples: 5, oranges: 10, grapes: 22 },
{ apples: 4, oranges: 12, grapes: 28 },
{ apples: 2, oranges: 19, grapes: 32 },
{ apples: 7, oranges: 23, grapes: 35 },
{ apples: 23, oranges: 17, grapes: 43 }
];
The target object should look as follows. its an Array of Array of objects:
var finaldats = [
[{ x: 0, y: 5 },
{ x: 1, y: 4 },
{ x: 2, y: 2 },
{ x: 3, y: 7 },
{ x: 4, y: 23 }
],
[{ x: 0, y: 10 },
{ x: 1, y: 12 },
...
My approach so far:
var inner = {}
inner["x"] ;
inner["y"] ;
dats.forEach(function(d,i) {
inner["x"] = i
inner["y"] = dats[i].apples;
});
This produces: Object {x: 4, y: 23}
Its always the last element of the input array, which is fine, since the object is constantly overwritten in each iteration.
At the moment I fail to push these objects, being created in each iteration into an array.
I thought of something like this, but it does not work:
var inner = {}
inner["x"] ;
inner["y"] ;
var outer = [];
dats.forEach(function(d,i) {
inner["x"] = i
inner["y"] = dats[i].apples;
outer.push(inner);
});
Use map:
The map() method creates a new array with the results of calling a
provided function on every element in this array.
var dats = [{ apples: 5, oranges: 10, grapes: 22},
{ apples: 4, oranges: 12, grapes: 28},
{ apples: 2, oranges: 19, grapes: 32},
{ apples: 7, oranges: 23, grapes: 35},
{ apples: 23, oranges: 17, grapes: 43}
];
var inner = dats.map(function(d, i) {
return {
x: i,
y: d.apples
}
});
document.write('<pre>' + JSON.stringify(inner, 0, 4) + '</pre>');
Edit:
To get the result for all the Keys you can use below snippet:
var dats = [{ apples: 5, oranges: 10, grapes: 22},
{ apples: 4, oranges: 12, grapes: 28},
{ apples: 2, oranges: 19, grapes: 32},
{ apples: 7, oranges: 23, grapes: 35},
{ apples: 23, oranges: 17, grapes: 43}
];
var inner = dats.map((o) => {
return Object.keys(o)
}).reduce((prev, curr) => {
return prev.concat(curr)
}).filter((col, i, array) => {
return array.indexOf(col) === i
}).map(function(k) {
return dats.map(function(a, i) {
return {
x: i,
y: a[k]
};
});
});
document.write('<pre>' + JSON.stringify(inner, 0, 4) + '</pre>');
Read more about map
While the other solution features only a part of the solution, here the complete solution with an array for the keys and two nested Array#map(), one for the keys ['apples', 'oranges', 'grapes'] and one for the values in the dats.
var dats = [{ apples: 5, oranges: 10, grapes: 22 }, { apples: 4, oranges: 12, grapes: 28 }, { apples: 2, oranges: 19, grapes: 32 }, { apples: 7, oranges: 23, grapes: 35 }, { apples: 23, oranges: 17, grapes: 43 }],
finaldats = ['apples', 'oranges', 'grapes'].map(function (k) {
return dats.map(function (a, i) {
return { x: i, y: a[k] };
});
});
document.write('<pre>' + JSON.stringify(finaldats, 0, 4) + '</pre>');

Categories