#javascript #ecmascript-6
Вопрос:
У меня есть массив, содержащий сведения о носителях:
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}
];
Я хочу обновить items
и printable
ценности таким carrier
образом, чтобы иметь
carrier=[
{"carrier_code":"ups","items":5,"printable":4},
{"carrier_code":"dhl","items":3,"printable":2},
{"carrier_code":"tnt","items":0,"printable":0}
];
Мне удалось достичь аналогичного результата с помощью map/filter/reduce, но для ситуации с одним объектом и одним массивом.
В то время как в этой ситуации я могу думать только о вложенном forEach
:
carriers.forEach(c =>
{
orders.forEach(o =>
{
c.items =o.carrier_code==c.carrier_code?1:0;
c.printable =o.carrier_code==c.carrier_codeamp;amp;o.printable==1?1:0;
}
)
});
console.log(carriers)
Но, возможно, это решение ES6
Мне было интересно, что ES9 может предложить «лучшее» решение,
Может ли кто-нибудь предложить более простой или элегантный способ достижения того же результата?
Ответ №1:
Чтобы уменьшить вычислительную сложность, сначала сгруппируйте carrier
по carrier_code
, затем вы можете выполнить итерацию orders
и сразу же найти совпадение ( O(n)
вместо O(n ^ 2)
).
Object.fromEntries
может использоваться для группировки носителей, начиная с 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);
Ответ №2:
В спецификации нет ничего, что превращало бы это в один(иш) вызов, но вы, безусловно, можете уменьшить эту O(n * m)
сложность до O(n m)
сложности, сначала подсчитав ваши заказы в ячейках, а затем назначив эти подсчеты вашим операторам:
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]));
Ответ №3:
Я бы сначала подсчитал и суммировал необходимые мне товары, а затем назначил их соответствующему перевозчику. Вот что я бы сделал:
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);
Ответ №4:
Вместо вызова вложенного массива.prototype.forEach (), который не является производительным
Вы можете сделать:
- Используйте Array.prototype.reduce() для создания
ordersHash
объекта, подобного:{ ups: { carrier_code: 'ups', items: 0, printable: 0 }, dhl: { carrier_code: 'dhl', items: 0, printable: 0 }, tnt: { carrier_code: 'tnt', items: 0, printable: 0 } }
- Затем объедините Object.values (), чтобы извлечь массив
result
Array.prototype.reduce()orders
для обновления свойствitems
иprintable
объектаordersHash
Код:
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)