Home > Enterprise >  ES9 javascript update array of objects from other array of objects
ES9 javascript update array of objects from other array of objects

Time:10-10

I have an array containing carriers details:

const carrier=[
                {"carrier_code":"ups","items":0,"printable":0},
                {"carrier_code":"dhl","items":0,"printable":0},
                {"carrier_code":"tnt","items":0,"printable":0}
              ];

Then another array containing orders:

const orders = [
                  {"order_id":"00101","carrier_code":"dhl","printable":0},
                  {"order_id":"00101","carrier_code":"ups","printable":1},
                  {"order_id":"00101","carrier_code":"dhl","printable":1},
                  {"order_id":"00101","carrier_code":"dhl","printable":1},
                  {"order_id":"00101","carrier_code":"ups","printable":1},
                  {"order_id":"00101","carrier_code":"ups","printable":0},
                  {"order_id":"00101","carrier_code":"ups","printable":1},
                  {"order_id":"00101","carrier_code":"ups","printable":1}
               ];

I want to update items and printable values in carrier in a way to have

carrier=[
            {"carrier_code":"ups","items":5,"printable":4},
            {"carrier_code":"dhl","items":3,"printable":2},
            {"carrier_code":"tnt","items":0,"printable":0}
        ];
          

I've been able to achieve a similar result using map/filter/reduce, but for a situation with one object and one array.

While for this situation I can only think to a nested forEach :

carriers.forEach(c =>
{
    orders.forEach(o =>
      {
          c.items =o.carrier_code==c.carrier_code?1:0;
          c.printable =o.carrier_code==c.carrier_code&&o.printable==1?1:0;
      }
    )
});
  
console.log(carriers)

But perhaps this is an ES6 solution

I was wondering that ES9 could offer a "better" solution,

Can somebody suggest an easier or more elegant way to achieve the same result?

CodePudding user response:

To reduce the computational complexity, first group the carrier by the carrier_code, then you can iterate over the orders and look up the match immediately (O(n) instead of O(n ^ 2)).

Object.fromEntries can be used to group the carriers, which is from ES2019.

const carrier=[{carrier_code:"ups",items:0,printable:0},{carrier_code:"dhl",items:0,printable:0},{carrier_code:"tnt",items:0,printable:0}],orders=[{order_id:"00101",carrier_code:"dhl",printable:0},{order_id:"00101",carrier_code:"ups",printable:1},{order_id:"00101",carrier_code:"dhl",printable:1},{order_id:"00101",carrier_code:"dhl",printable:1},{order_id:"00101",carrier_code:"ups",printable:1},{order_id:"00101",carrier_code:"ups",printable:0},{order_id:"00101",carrier_code:"ups",printable:1},{order_id:"00101",carrier_code:"ups",printable:1}];

const carrierByCode = Object.fromEntries(
  carrier.map(c => [c.carrier_code, c])
);
for (const order of orders) {
  const carrier = carrierByCode[order.carrier_code];
  carrier.items  ;
  if (order.printable) carrier.printable  ;
}
console.log(carrier);

CodePudding user response:

Nothing in the spec that turns this into a single(ish) call, but you can certainly reduce that O(n * m) complexity to O(n m) complexity by first bin-counting your orders, then assigning those counts to your carriers:

const counters = {};

// run your bin counting in O(n)
orders.forEach({carrier_code} => {
  if (counters[carrier_code] === undefined) {
    counters[carrier_code] = 0;
  }
  counters[carrier_code]  ;
});

// And then assign those counts in O(m)
carriers.forEach(c => (c.items = counters[c.carrier_code]));

CodePudding user response:

I would first count and sum the items i need and then assign them to corresponding carrier. This is what i would do:

const carrier = [
  { carrier_code: "ups", items: 0, printable: 0 },
  { carrier_code: "dhl", items: 0, printable: 0 },
  { carrier_code: "tnt", items: 0, printable: 0 }
];
const orders = [
  { order_id: "00101", carrier_code: "dhl", printable: 0 },
  { order_id: "00101", carrier_code: "ups", printable: 1 },
  { order_id: "00101", carrier_code: "dhl", printable: 1 },
  { order_id: "00101", carrier_code: "dhl", printable: 1 },
  { order_id: "00101", carrier_code: "ups", printable: 1 },
  { order_id: "00101", carrier_code: "ups", printable: 0 },
  { order_id: "00101", carrier_code: "ups", printable: 1 },
  { order_id: "00101", carrier_code: "ups", printable: 1 }
];

var counts = orders.reduce((p, c) => {
  if (!p.hasOwnProperty(c.carrier_code))
    p[c.carrier_code] = { items: 0, printable: 0 };
  p[c.carrier_code].items  ;
  p[c.carrier_code].carrier_code=c.carrier_code;
  p[c.carrier_code].printable  = c.printable;
  return p;
}, {});
carrier.forEach((e, index) => carrier[index] = counts[e.carrier_code] || carrier[index]);

console.log(carrier);

CodePudding user response:

Instead of calling a nested Array.prototype.forEach() which is not performant

You can do:

  1. Use Array.prototype.reduce() to create a ordersHash object like:

    {
      ups: { carrier_code: 'ups', items: 0, printable: 0 },
      dhl: { carrier_code: 'dhl', items: 0, printable: 0 },
      tnt: { carrier_code: 'tnt', items: 0, printable: 0 }
    }
    
  2. Then combine Object.values() to extract the array result of Array.prototype.reduce()ing the orders to update properties items and printable of object ordersHash

Code:

const carrier = [{ carrier_code: 'ups', items: 0, printable: 0 },{ carrier_code: 'dhl', items: 0, printable: 0 },{ carrier_code: 'tnt', items: 0, printable: 0 }]
const orders = [{ order_id: '00101', carrier_code: 'dhl', printable: 0 },{ order_id: '00101', carrier_code: 'ups', printable: 1 },{ order_id: '00101', carrier_code: 'dhl', printable: 1 },{ order_id: '00101', carrier_code: 'dhl', printable: 1 },{ order_id: '00101', carrier_code: 'ups', printable: 1 },{ order_id: '00101', carrier_code: 'ups', printable: 0 },{ order_id: '00101', carrier_code: 'ups', printable: 1 },{ order_id: '00101', carrier_code: 'ups', printable: 1 }]

const carrierHash = carrier.reduce((a, c) => {
  a[c.carrier_code] = a[c.carrier_code] || c
  return a
}, {})

const result = Object.values(
  orders.reduce((a, { carrier_code, printable }) => {
    a[carrier_code].items  = 1
    a[carrier_code].printable  = printable
    return a
  }, carrierHash)
)

console.log(result)

  • Related