У меня есть массив объектов, которые нужно суммировать на основе ключевого суффикса

#javascript #node.js #lodash

Вопрос:

Это исходный массив:

 [
    {
      id: robin, 
      savings: 5500,
      cost: 1200
    },
    {
     id: robin_1,
     savings: 50,
     cost: 100
    },
    {
    id: robin_2,
     savings: 50,
     cost: 150
    },
    {
      id: steve, 
      savings: 100,
      cost: 1000
    },
    {
     id: steve_1,
     savings: 50,
     cost: 550
    },
    {
    id: steve_2,
     savings: 50,
     cost: 150
    },
]
 

Я пытаюсь получить результат ниже ожидаемого .

 {
 robin :{
   allTime:{
      savings: 5500,
      cost: 1200,
    },
   today:{
     savings: 100,
     cost: 250 
    }
  },
  steve:{
   allTime: {
     savings:100,
     cost: 1000
   },
   today: {
     savings: 100,
     cost: 700
   }
  }
}

 

В основном, когда идентификатор-это только робин, установите вывод в ключе allTime, и когда после робина есть некоторые суффиксы, такие как 1,2,3, затем суммируйте их и установите в «сегодня».

Пробовали, обычно зацикливая их и группируя с помощью _.sumBy (), как показано ниже, но потерпели неудачу.

 var output = _.groupBy(resultSet, value => value.id)
               .map((objs, key) => (
                { 'id': key,
                  'savings': _.sumBy(objs,'savings'), 
                  'cost': _.sumBy(objs, 'cost'))
                }
                .value();
 

Комментарии:

1. «Пробовали, обычно зацикливая их» не могли бы вы, пожалуйста, включить свои попытки? Таким образом, мы можем помочь вам понять их и дать ответ на ваш вопрос.

2. @Reyno Добавил мою попытку . Было бы очень полезно, если бы вы могли мне помочь.

Ответ №1:

Мне удалось сделать это так, используя array#reduce :

 let data = [
    { id: 'robin', savings: 5500, cost: 1200 },
    { id: 'robin_1', savings: 50, cost: 100 },
    { id: 'robin_2', savings: 50, cost: 150 },
    { id: 'steve', savings: 100, cost: 1000 },
    { id: 'steve_1', savings: 50, cost: 550 },
    { id: 'steve_2', savings: 50, cost: 150 },
];

let newData = data.reduce((acc, { id, savings, cost }) => {
    let [pre, suff] = id.split('_');

    if (!acc[pre]) acc[pre] = { allTime: {}, today: { savings: 0, cost: 0 } };
    if (!suff) acc[pre].allTime = { savings, cost };
    else (acc[pre].today.savings  = savings), (acc[pre].today.cost  = cost);

    return acc;
}, {});

console.log(newData); 

И вот так, используя for...of петлю:

 let data = [
    { id: 'robin', savings: 5500, cost: 1200 },
    { id: 'robin_1', savings: 50, cost: 100 },
    { id: 'robin_2', savings: 50, cost: 150 },
    { id: 'steve', savings: 100, cost: 1000 },
    { id: 'steve_1', savings: 50, cost: 550 },
    { id: 'steve_2', savings: 50, cost: 150 },
];

let newData = {};
for ({ id, savings, cost } of data) {
    let [pre, suff] = id.split('_');

    if (!newData[pre]) newData[pre] = { allTime: {}, today: { savings: 0, cost: 0 } };
    if (!suff) newData[pre].allTime = { savings, cost };
    else (newData[pre].today.savings  = savings), (newData[pre].today.cost  = cost);
}

console.log(newData) 

Ответ №2:

Попробуйте сделать это циклически, уменьшив

 const data = [
    {
      id: "robin", 
      savings: 5500,
      cost: 1200
    },
    {
     id: "robin_1",
     savings: 50,
     cost: 100
    },
    {
    id: "robin_2",
     savings: 50,
     cost: 150
    },
    {
      id: "steve", 
      savings: 100,
      cost: 1000
    },
    {
     id: "steve_1",
     savings: 50,
     cost: 550
    },
    {
    id: "steve_2",
     savings: 50,
     cost: 150
    },
];
    const res = data.reduce((acc, val) => {
          const splitVal =  val.id.split("_")[0];
          if(acc[val.id] || acc[splitVal]){
               acc[splitVal].today.savings =val.savings;
               acc[splitVal].today.cost =val.cost;
          }else{
               acc[val.id] = {
                    allTime:{
                         savings: val.savings,
                         cost: val.cost,
                    },
                    today:{
                         savings: 0,
                         cost: 0 
                    }
               }
          }
          return acc;
    }, {});
    console.log(res); 

Ответ №3:

Я думаю, что я бы пошел Array.prototype.reduce() вот так:

 const input = [
  { id: 'robin', savings: 5500, cost: 1200 },
  { id: 'robin_1', savings: 50, cost: 100 },
  { id: 'robin_2', savings: 50, cost: 150 },
  { id: 'steve', savings: 100, cost: 1000 },
  { id: 'steve_1', savings: 50, cost: 550 },
  { id: 'steve_2', savings: 50, cost: 150 },
  { id: 'bob', savings: 1000, cost: 300 },
  { id: 'mark_1', savings: 50, cost: 150 }
];

const output = input.reduce((outObj, item) => {
  const { savings, cost } = item;
  const [mainKey, suffix] = item.id.split('_');
  const subKey = suffix === undefined ? 'allTime' : 'today';

  if (!outObj.hasOwnProperty(mainKey)) {
    outObj[mainKey] = {
      [subKey]: { savings, cost }
    }
  } else {
    if (!outObj[mainKey].hasOwnProperty(subKey)) {
      outObj[mainKey][subKey] = { savings, cost }
    } else {
      outObj[mainKey][subKey].savings  = savings;
      outObj[mainKey][subKey].cost  = cost;
    }
  }

  return outObj;
}, {})

//test
console.log(output); 

При таком подходе вы не «жестко кодируете» свойства allTime и today в каждую запись выходного объекта; вместо этого вы динамически добавляете их только в том случае, если/где они необходимы (см. Примеры с bob и mark где добавляется только allTime или today )