skip to Main Content

I am using this reduce by i need to calculate not only for category but for level too.
so I will have an array of objects that will include count of mainUnits and subUnits for each category and each level so for example

{
    category: 1,
    mainUnits: 14,
    subUnits: 15,
    levelA: {
        mainUnits: 4,
        subUnits: 6
    },
    levelB: {
        mainUnits: 14,
        subUnits: 15
    }
}
const input = [
  {
    category: 1,
    level: 'B',
    mainUnits: 5,
    subUnits: 3,
  },
  {
    category: 1,
    level: 'B',
    mainUnits: 9,
    subUnits: 12,
  },
  {
    category: 2,
    level: 'A',
    mainUnits: 4,
    subUnits: 6,
  },
  {
    category: 2,
    level: 'B',
    mainUnits: 2,
    subUnits: 4,
  },
];

const result = input.reduce((result, item) => {
  const existing = result.find((x) => x.category === item.category);
  if (existing) {
    existing.mainUnits += item.mainUnits;
    existing.subUnits += item.subUnits;
  } else {
    result.push(item);
  }

  return result;
}, []);

console.log(result);

3

Answers


  1. You could group with an object and get the values as result. Inside check for level and add an object with properties with zero values.

    Then add for outer and nested level the units.

    const
        input = [{ category: 1, level: 'B', mainUnits: 5, subUnits: 3 }, { category: 1, level: 'B', mainUnits: 9, subUnits: 12 }, { category: 2, level: 'A', mainUnits: 4, subUnits: 6 }, { category: 2, level: 'B', mainUnits: 2, subUnits: 4 }],
        result = Object.values(input.reduce((r, { category, level, ...o }) => {
            const 
                addTo = object => key => object[key] = (object[key] || 0) + o[key],
                keys = ['mainUnits', 'subUnits'];
    
            r[category] ??= { category};
            keys.forEach(addTo(r[category]));
            keys.forEach(addTo(r[category]['level' + level] ??= {}));
            return r;
        }, {}));
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  2. Lodash approach using groupBy, sumBy and mapValues:

    const input = [
      {
        category: 1,
        level: 'B',
        mainUnits: 5,
        subUnits: 3,
      },
      {
        category: 1,
        level: 'B',
        mainUnits: 9,
        subUnits: 12,
      },
      {
        category: 2,
        level: 'A',
        mainUnits: 4,
        subUnits: 6,
      },
      {
        category: 2,
        level: 'B',
        mainUnits: 2,
        subUnits: 4,
      },
    ];
    
    const result = _(input)
      .groupBy('category')
      .map((items, category) => ({
        category: parseInt(category),
        mainUnits: _.sumBy(items, 'mainUnits'),
        subUnits: _.sumBy(items, 'subUnits'),
        ..._.mapValues(_.groupBy(items, 'level'), (levelItems) => ({
          mainUnits: _.sumBy(levelItems, 'mainUnits'),
          subUnits: _.sumBy(levelItems, 'subUnits'),
        })),
      }))
      .value();
    
    console.log(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
    Login or Signup to reply.
  3. I have added a couple more lines of code to your working snippet and it does the job. Let me know if I missed something.

    const input = [
      {
        category: 1,
        level: "B",
        mainUnits: 5,
        subUnits: 3,
      },
      {
        category: 1,
        level: "B",
        mainUnits: 9,
        subUnits: 12,
      },
      {
        category: 2,
        level: "A",
        mainUnits: 4,
        subUnits: 6,
      },
      {
        category: 2,
        level: "B",
        mainUnits: 2,
        subUnits: 4,
      },
    ];
    
    const result = input.reduce((result, item) => {
      const existing = result.find((x) => x.category === item.category);
      if (existing) {
        existing.mainUnits += item.mainUnits;
        existing.subUnits += item.subUnits;
        if (existing["level" + item.level]) {
          existing["level" + item.level]["mainUnits"] += item.mainUnits;
          existing["level" + item.level]["subUnits"] += item.subUnits;
        } else {
          existing["level" + item.level] = {
            mainUnits: item.mainUnits,
            subUnits: item.subUnits,
          };
        }
      } else {
        const { category, level, mainUnits, subUnits } = item;
        const obj = {
          category,
          mainUnits,
          subUnits,
          ["level" + level]: {
            mainUnits,
            subUnits,
          },
        };
        result.push(obj);
      }
    
      return result;
    }, []);
    
    console.log(result);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search