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:
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 } }
Then combine Object.values() to extract the array
result
of Array.prototype.reduce()ing theorders
to update propertiesitems
andprintable
of objectordersHash
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)