How do I get the total sum of nested arrays in Reactjs? - javascript

I want to get the total price of nested arrays in a specific category e.g: Hot Drinks.
Here is a sample of what I have now, so I want to filter out and get the total price of Hot Drinks Category only.
[
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
]

You can apply a filter method on the array and then just add the values on the filtered array. Something like below:
let prod = [
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
];
function getPriceByCategory(category, products) {
let price = 0;
products.forEach(orders => {
orders.orderItems.filter(order => order.category == category).forEach(item => {
price += item.price;
});
});
return price;
}
const totalPrice = getPriceByCategory('Hot Drinks', prod);
alert(totalPrice);
Sample JS Fiddle: https://jsfiddle.net/sagarag05/qwzju53f/9/

const filterBy = 'Hot Drinks';
const items = [
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
]
const sumOf = (items, filterBy) => {
let totalPrice = 0;
items.forEach(item => {
item.orderItems.forEach(orderItem => {
if (orderItem.category === filterBy) {
totalPrice += orderItem.price;
}
})
})
return totalPrice;
}
console.log(sumOf(items, filterBy))

let sum = 0;
allOrders.forEach(order => {
order.orderItems.forEach(item => {
if(item.category=='Hot Drinks') {
sum+ = item.price * item.qty
}});
});
sum has the total price for Hot Drinks

Assuming you named that information as data:
Generate a big array of all the "orderItems"
For each of those elements sum the price if the category is "Hot Drinks"
const totalPrice = data
.reduce((acc, { orderItems }) => [...acc, ...orderItems], [])
.reduce((acc, { category, price }) => category === "Hot Drinks" ? acc + price : acc, 0);
console.log(totalPrice); // 10

Use flatMap and reduce or alternatively using forEach and destructuring
const total = (arr, text) =>
arr
.flatMap(({ orderItems }) => orderItems)
.reduce((acc, { category, price }) =>
(acc + (category === text ? price : 0)), 0);
// alternatively
const total2 = (arr, text, acc = 0) => {
arr.forEach(({ orderItems }) =>
orderItems.forEach(
({ category, price }) => (category === text && (acc += price))
)
);
return acc;
};
const data = [
{
totalPrice: 30,
_id: "6014fa4324e125599eaa72b5",
orderItems: [
{
_id: "6014fa4324e125599eaa747ss",
category: "Breakfast",
name: "food name 1",
price: 3,
qty: 1,
},
{
_id: "6014fa4324e125599eaa747s5",
category: "Hot Drinks",
name: "drink name 1",
price: 3,
qty: 5,
},
{
_id: "6014fa4324e125599eaa74767",
category: "Hot Drinks",
name: "drink name 2",
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: "6014fa4324e125599eaa7276e",
orderItems: [
{
_id: "6014fa4324e125599eaa747ss",
category: "Hot Drinks",
name: "drink name 1",
price: 3,
qty: 6,
},
],
},
];
console.log(total(data, 'Hot Drinks'))
console.log(total2(data, 'Hot Drinks'))

Related

Question from a beginner: Unexpected JS behavior [duplicate]

I'm trying to convert an array of objects where i return duplicated objects if the object properties quantity is greater than 1.
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
// desired return
[
{ id: 1, name: "Scissor", price: 2 }
{ id: 1, name: "Scissor", price: 2 }
{ id: 1, name: "Scissor", price: 2 }
{ id: 2, name: "Hat", price: 6.5}
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
]
My code:
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
let newObjects= [];
Object.entries(objects).forEach(([key, value]) => {
for (let i=0; i < value.quantity; i++){
newObjects.push({ id: value.id, name: value.name, price: value.price})
}
});
console.log(newObjects);
So my code above does work, does return what i wanted, however i feel like there is a better/smoother and more of ES6 and beyond method. Could anyone please suggest a better way?
You could use .fill() and .flatMap().
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
let newObjects = objects.flatMap(e=>
Array(e.quantity).fill({id: e.id, name: e.name, price: e.price})
);
console.log(newObjects);
You can use an array reduce along with an array fill.
The map is required only if you want to have unique references otherwise you can fill using the same object.
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
const output = objects.reduce((a, c) => {
return a.concat(Array(c.quantity).fill({}).map(x=>({
id: c.id,
name: c.name,
price: c.price
})))
}, []);
console.log(output)

How to groupBy with sum using lodash

I have productId which is an array of values.
const groupByvalue= [1, 2];
I have products that have multiple product arrays.
const products = [
{
id: 1,
name: 'milk',
qty: 2
},
{
id: 2,
name: 'butter',
qty: 2
},
{
id: 3,
name: 'milk',
qty: 2
},
{
id: 2,
name: 'butter',
qty: 2
},
{
id: 1,
name: 'milk',
qty: 2
},
{
id: 3,
name: 'butter',
qty: 2
},
{
id: 1,
name: 'milk',
qty: 2
},
{
id: 3,
name: 'butter',
qty: 2
}
];
const groupByKey = 'id';
I need to group the products based on the product's id.
conditions
i)groupBy should be based on the groupByvalue with groupBykey array (only groupBy 1 , 2)
ii) after the group it should sum all the qty
expected
[
{
id: 1,
name : "milk",
qty : sum of all qty
},
{
id: 2,
name : "butter",
qty : sum of all qty
}
];
Thanks!!
Using Lodash
var _ = require('lodash');
var groupByValue = [1, 2];
var groupByKey = 'id';
const products = [
{ id: 1, name: 'milk', qty: 2 },
{ id: 2, name: 'butter', qty: 2 },
{ id: 3, name: 'milk', qty: 2 },
{ id: 2, name: 'butter', qty: 2 },
{ id: 1, name: 'milk', qty: 2 },
{ id: 3, name: 'butter', qty: 2 },
{ id: 1, name: 'milk', qty: 2 },
{ id: 3, name: 'butter', qty: 2 }
]
const ans = _(products)
.groupBy(groupByKey)
.map((product) => {
if(groupByValue.includes(product[0].id)){
return {
id: product[0].id,
name: product[0].name,
qty: _.sumBy(product, 'qty')
}
}
})
.value()
console.log(ans.filter(item => item));
Output :-
[ { id: 1, name: 'milk', qty: 6 }, { id: 2, name: 'butter', qty: 4 } ]
No need for lodash whatsoever, this is a native .reduce() task. You may do like;
var groupByValue = [1, 2],
groupByKey = 'id',
products = [ { id : 1
, name: 'milk'
, qty : 2
}
, { id : 2
, name: 'butter'
, qty : 2
}
, { id : 3
, name: 'milk'
, qty: 2
}
, { id : 2
, name: 'butter'
, qty : 2
}
, { id : 1
, name: 'milk'
, qty : 2
}
, { id : 3
, name: 'butter'
, qty : 2
}
, { id : 1
, name: 'milk'
, qty : 2
}
, { id : 3
, name: 'butter'
, qty : 2
}
],
interim = products.reduce( (r,p) => ( groupByValue.includes(p[groupByKey]) && (r[p[groupByKey]] ? r[p[groupByKey]].qty += p.qty
: r[p[groupByKey]] = Object.assign({},p))
, r
)
, {}
),
result = Object.values(interim);
console.log(result);
The milk products with id:3 doesn't count.
I would filter the array first, and then make the map,
this can be done in single .reduce(...) function, but its more readable using lodash:
const _ = require('lodash');
const groupByValue = [1, 2];
const groupByKey = 'id';
const products = [
{ id: 1, name: 'milk', qty: 1 },
{ id: 2, name: 'butter', qty: 2 },
{ id: 3, name: 'cheese', qty: 4 },
{ id: 2, name: 'butter', qty: 5 },
{ id: 1, name: 'milk', qty: 3 },
{ id: 3, name: 'cheese', qty: 6 },
{ id: 1, name: 'milk', qty: 1 },
{ id: 3, name: 'cheese', qty: 7 }
];
const result = _(products)
.filter(itm => groupByValue.includes(itm.id))
.groupBy(groupByKey)
.map(arr => {
const { id, name } = arr[0];
return { id, name, qty: _(arr).sumBy('qty') };
})
.value();
console.log(result);
// output: [{ id: 1, name: 'milk', qty: 5},{id: 2, name: 'butter', qty: 7}]

Hot Categories / inventory checker

We were given this activity in school to find categories that has no more stocks. Hot categories should be unique and without repeating categories.
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
Here is my code so far. I am only getting one category and cannot display the 2nd category with 0 stocks.
function findHotCategories(items) {
let ilen = items.length
for(let i = 0; i < ilen; i++){
if(items[i].stocks === 0){
let newArr = items[i].category
return [newArr]
}
}
};
// dont forget to UpVoted (:
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
const emptyStocks = [];
for( let a in items ){ if( items[a].stocks < 1 ) emptyStocks.push(items[a]); }
console.log( emptyStocks );
You return in the loop so the function ends where it matches the first item.
You should return after the loop
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
function findHotCategories(items) {
let newArr = [];
let ilen = items.length
for(let i = 0; i < ilen; i++){
if(items[i].stocks === 0){
newArr.push(items[i].category)
}
}
return [...new Set(newArr)];
}
console.log(findHotCategories(items));
Here it is:
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
const totalStocks = items.reduce((acc, prev) => {
if (!acc[prev.category]) {
return { ...acc, [prev.category]: prev.stocks }
}
return { ...acc, [prev.category]: acc[prev.category] + prev.stocks }
}, {})
const emptyStocks = Object.keys(totalStocks).filter(key => totalStocks[key] === 0)
console.log(emptyStocks)
My short answer with using filter and map function.
function findHotCategories(items) {
const result = items.filter(e => e.stocks === 0).map(e => e.category);
return [...new Set(result)];
}

How to create a nested array of object from an array of objects

How Can I loop through this array of objects and change it so that the individual menu items are nested in the object menu_name?
const menus = [
{ menu_name: 'Entre', id:0 },
{
name: 'Soup',
price: 14.99,
id:1
},
{
name: 'Chips & Salsa',
price: 7.99,
id:2
},
{
name: 'Chicken Nuggets',
price: 12.99,
id:3
},
{ menu_name: 'Sides', id:4 },
{
name: 'Fries',
price: 4.99,
id:5
},
{
name: 'Drinks',
price: 2.99,
id:6
},
{
name: 'Onion Rings',
price: 5.99,
id:7
},
];
the end result should look like this for each menu_name object, where an array of menus is nested in the menu_name object
{
menu_name: 'Sides',
menu: [
{
name: 'Fries',
price: 4.99,
},
{
name: 'Drinks',
price: 2.99,
},
{
name: 'Onion Rings',
price: 5.99,
},
],
},
You can easily achieve this using reduce and object destructuring
const menus = [
{ menu_name: "Entre", id: 0 },
{
name: "Soup",
price: 14.99,
id: 1,
},
{
name: "Chips & Salsa",
price: 7.99,
id: 2,
},
{
name: "Chicken Nuggets",
price: 12.99,
id: 3,
},
{ menu_name: "Sides", id: 4 },
{
name: "Fries",
price: 4.99,
id: 5,
},
{
name: "Drinks",
price: 2.99,
id: 6,
},
{
name: "Onion Rings",
price: 5.99,
id: 7,
},
];
const result = menus.reduce((acc, curr) => {
const { menu_name } = curr;
if (menu_name) {
acc.push({ menu_name, menu: [] });
} else {
const { name, price } = curr;
acc[acc.length - 1].menu.push({ name, price });
}
return acc;
}, []);
console.log(result);
var newMenu = [];
menus.forEach(menu=>{
if(menu.menu_name){
newMenu.push({...menu, menu: []})
}else{
newMenu[newMenu.length-1].menu.push(menu)
}
});

ES6: Populate object value with a value from another object when ID is present

I would like to populate the value 'discount' for a product with the discount ID value from the array discounts, if the respective product ID exists as a value in the Discounts object.
const products = [{
id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d",
name: "SANTO - Schnürstiefelette",
price: 199.95,
discount: 0,
},
{
id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5",
name: "AIR FORCE 1 07 LV8 - Sneaker low",
price: 109.95,
discount: 0,
},
{
id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e",
name: "DUFF 9.0 - Sporttasche",
price: 34.95,
discount: 0,
},
{
id: "471ad894-150b-4a2b-881c-a9a4dbc4b401",
name: "Strickpullover",
price: 20.99,
discount: 0,
},
];
const discounts = [{
id: "5791ae04-a704-4f44-808b-de5ddb8812b5",
name: "Christmas discount",
productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"],
active: true
},
{
id: "5791ae04-a704-4f44-808b-de5ddb8812e6",
name: "Christmas discount 2",
productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"],
active: true
}
];
At the end i need it like:
const products = [{
id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d",
name: "SANTO - Schnürstiefelette",
price: 199.95,
discount: '5791ae04-a704-4f44-808b-de5ddb8812e6',
},
...
...
You could use map() to transform products array. And find() and includes() to check if discount exists for a product.
const products = [{ id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d", name: "SANTO - Schnürstiefelette", price: 199.95, discount: 0, }, { id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5", name: "AIR FORCE 1 07 LV8 - Sneaker low", price: 109.95, discount: 0, }, { id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e", name: "DUFF 9.0 - Sporttasche", price: 34.95, discount: 0, }, { id: "471ad894-150b-4a2b-881c-a9a4dbc4b401", name: "Strickpullover", price: 20.99, discount: 0, }, ];
const discounts = [{ id: "5791ae04-a704-4f44-808b-de5ddb8812b5", name: "Christmas discount", productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"], active: true }, { id: "5791ae04-a704-4f44-808b-de5ddb8812e6", name: "Christmas discount 2", productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"], active: true } ];
let result = products.map(product => {
let discount = discounts.find(item => item.productIds.includes(product.id));
return {
...product,
"discount": discount ? discount.id : product.discount
};
});
console.log(result);
You could store the discounts in a Map and map the object with a new discount object, if necessary.
var products = [{ id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d", name: "SANTO - Schnürstiefelette", price: 199.95, discount: 0 }, { id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5", name: "AIR FORCE 1 07 LV8 - Sneaker low", price: 109.95, discount: 0 }, { id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e", name: "DUFF 9.0 - Sporttasche", price: 34.95, discount: 0 }, { id: "471ad894-150b-4a2b-881c-a9a4dbc4b401", name: "Strickpullover", price: 20.99, discount: 0 }],
discounts = [{ id: "5791ae04-a704-4f44-808b-de5ddb8812b5", name: "Christmas discount", productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"], active: true }, { id: "5791ae04-a704-4f44-808b-de5ddb8812e6", name: "Christmas discount 2", productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"], active: true }],
ids = discounts.reduce((m, { id, productIds }) => productIds.reduce((n, pid) => n.set(pid, id), m), new Map);
products = products.map(p => Object.assign({}, p, ids.has(p.id) && { discount: ids.get(p.id) }));
console.log(products);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nested loop through both products and discounts array, if the product id is included inside the productIds array of any of the objects in the discounts array, assign the discount id to the product discount.
for (let product of products) {
for (let discount of discounts) {
if (discount.productIds.includes(product.id)){
product.discount = discount.id;
break;
}
}
}

Categories