ES9 javascript обновляет массив объектов из другого массива объектов

#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 (), который не является производительным

Вы можете сделать:

  1. Используйте 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 }
    }
     
  2. Затем объедините 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)