Cain Nuke
Cain Nuke

Reputation: 3079

How to check an array of objects against another one?

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?

Upvotes: 0

Views: 76

Answers (4)

Carsten Massmann
Carsten Massmann

Reputation: 28196

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

Upvotes: 1

pilchard
pilchard

Reputation: 12919

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

Upvotes: 1

Christian Vincenzo Traina
Christian Vincenzo Traina

Reputation: 10384

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

Upvotes: 2

Alex Wauters
Alex Wauters

Reputation: 122

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.

Upvotes: 0

Related Questions