0

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 won't exceed client's credit. I'm 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 didn't work. What is the right approach?

2
  • I so want to tell you and earn an easy upvote, but this is such an awesome exercise to learn how to program. I don't want to spoil it. Please, find the right solution yourselves. Commented Nov 26, 2022 at 22:32
  • 1
    Yeah well, then that would totally defeat the purpose of this site... Commented Nov 26, 2022 at 22:34

4 Answers 4

2

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}`);

Sign up to request clarification or add additional context in comments.

7 Comments

seems odd to combine the item details into the cart, if price changes in one it won't in the other. Better to maintain separation and just create a lookup.
The source must be separated, but to calculate an aggregate you need to... aggregate them :) there's nothing odd at all
Just to be clear, the variable joined will be discarded after the calculation, you'll still use your items and cart for other stuff. That's very common in functional programming
But why create a throw away when you could create a single lookup table to aggregate against in the future?
hi, the code seems to work very well though I get a warning like this: expected an identifier and instead saw and '?' at this part of the code ? 0)*(curr.qty ?? 0), 0);
|
1

I am a little late in the game, but maybe the following snippet is still of interest? It picks up the idea of creating a lookup object itms and for each shopping cart entry it also combines two objects into a new one with a subtotal subt, so you can easliy create a meaningfull shopping cart table. The variable ttl is updated alongside and contains the total sum:

const items = [
 {
  "id": "001",
  "name": "apple",
  "price": 500
},
{
  "id": "002",
  "name": "banana",
  "price": 700
},
{
  "id": "003",
  "name": "pear",
  "price": 200
 }
],
  cart = [{
  "id": "001",
  "qty": 2
},
{
  "id": "002",
  "qty": 3
},
{
  "id": "003",
  "qty": 4
}
];
// Turn the items array into an object, facilitating a fast lookup:
const itms=items.reduce((a,c)=>(a[c.id]=c,a),{});
let ttl=0;
// calculate the totals:
const res=cart.map(c=>{
  const p=itms[c.id], subt=c.qty*p.price;
  ttl+=subt;
  return {...c,...p,subt}
})

// Show the result:
console.log(res,ttl);

Comments

1

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

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.