Hi,
I have one array of objects with all items and their respective price like this:
var items = [
{
"id": "001",
"name": "apple",
"price": 500
},
{
"id": "002",
"name": "banana",
"price": 700
},
{
"id": "003",
"name": "pear",
"price": 200
}
];
then I have a client's car like this:
var cart = [{
"id": "001",
"qty": 2
},
{
"id": "002",
"qty": 3
},
{
"id": "003",
"qty": 4
}
];
client's credit is stored in a variable. I want to check the second array against the first one to get the total of the cart and make sure it wont exceed client's credit. Im not sure how to do it though. I tried:
var mytotal=cart.map(d => {
var total=0;
items.forEach(rm => {
total = total (d.qty*rm.price);
} return total;
});
if(credit >= total) {//dosomething}
but it didnt work. What is the right approach?
Thank you.
CodePudding user response:
You can divide your problem into two tasks: join and sum.
Join
const joined = items.map(item => ({...item, ...cart.find(c => c.id === item.id)}));
Note that in case the id won't match, find
will return null
, and the spread (...
) will result in no change to the object
Sum
const sum = joined.reduce((sum, curr) => sum = curr.price * curr.qty, 0);
A safer version would be:
const sum = joined.reduce((sum, curr) => sum = (curr.price ?? 0) * (curr.qty ?? 0), 0);
var items = [
{
"id": "001",
"name": "apple",
"price": 500
},
{
"id": "002",
"name": "banana",
"price": 700
},
{
"id": "003",
"name": "pear",
"price": 200
}
];
var cart = [{
"id": "001",
"qty": 2
},
{
"id": "002",
"qty": 3
},
{
"id": "003",
"qty": 4
}
];
const joined = items.map(item => ({...item, ...cart.find(c => c.id === item.id)}));
const sum = joined.reduce((sum, curr) => sum = curr.price * curr.qty, 0);
console.log(`joined object is: `, joined);
console.log(`sum is: ${sum}`);
CodePudding user response:
In your attempt, you're applying the map function to the cart array. Map applies the function to each element of the array, and returns the new array. The function total = 0 etc is being applied for each element separately.
In the map/reduce way of working, try getting the proper price of each cart element first with map, and then summarize using reduce. Map/reduce is just one of many ways to solve this issue, you could also do it iteratively with a for loop like you were trying within your map function.
CodePudding user response:
To implement a reusable and efficient solution you can create a lookup table on the items
array, here using a Map
, which allows you to directly access the item by id
.
const itemLookup = new Map(items.map((item) => [item.id, item]))
// Map(3) {
// '001' => { id: '001', name: 'apple', price: 500 },
// '002' => { id: '002', name: 'banana', price: 700 },
// '003' => { id: '003', name: 'pear', price: 200 }
// }
You can then create a getCartTotal
helper which will use the lookup table to total the cart passed to it. (Here we are assuming that any item that will be in the cart will also be in the items array, but for safety you could add optional chaining, t = (itemLookup.get(id)?.price ?? 0) * qty
)
const getCartTotal = (cart) => {
return cart.reduce((t, { id, qty }) => (
t = itemLookup.get(id).price * qty
), 0);
}
The result allows you to efficiently re-sum the cart whenever it changes.
const items = [{ "id": "001", "name": "apple", "price": 500 }, { "id": "002", "name": "banana", "price": 700 }, { "id": "003", "name": "pear", "price": 200 }];
const itemLookup = new Map(items.map(({ id, ...item }) => [id, { id, ...item }]));
const getCartTotal = (cart) => {
return cart.reduce((total, { id, qty }) => (
total = itemLookup.get(id).price * qty
), 0);
}
const cart = [{ "id": "001", "qty": 2 }, { "id": "002", "qty": 3 }, { "id": "003", "qty": 4 }];
console.log(getCartTotal(cart)); // 3900
cart[0].qty = 2;
console.log(getCartTotal(cart)); // 4900