Ikzer
Ikzer

Reputation: 539

Aggregate multiple values in of javascript

I want to reduce an array of objects like this:

var data = [{
    item: "Item 1",
    pages: 30,
    chapters: 3
    },
    {
    item: "Item 1",
    pages: 50,
    chapters: 3
    },
    {
    item: "Item 2",
    pages: 10,
    chapters: 3
    }
    ]

But aggregating two "fields", so in this case it should end like this:

  [
    {item: "Item 1", pages: 80, chapters: 6},
    {item: "Item 2", pages: 10, chapters: 3}
  ]

I've tried with a reduce but I can't aggregate more than one field:

data.reduce((acc,cur) => {
    acc[cur.item][pages] = acc[cur.item][pages] + cur.item.pages || cur.item.pages
    acc[cur.item][chapters] = acc[cur.item][chapters] + cur.item.chapters || cur.item.chapters
    return acc
},{})

But this throws errors since it doesn't find the pages item in the accumulator.

Is it possible to reduce aggregating more than one field of data?

Upvotes: 1

Views: 56

Answers (2)

Sash Sinha
Sash Sinha

Reputation: 22473

You can achieve this by using reduce and properly initializing the accumulator:

const data = [
  { item: "Item 1", pages: 30, chapters: 3 },
  { item: "Item 1", pages: 50, chapters: 3 },
  { item: "Item 2", pages: 10, chapters: 3 }
];

let result = data.reduce((acc, cur) => {
  if (!acc[cur.item]) {
    acc[cur.item] = { item: cur.item, pages: 0, chapters: 0 };
  }
  acc[cur.item].pages += cur.pages;
  acc[cur.item].chapters += cur.chapters;
  return acc;
}, {});

result = Object.values(result);
console.log(result);

Upvotes: 0

JsCoder
JsCoder

Reputation: 1733

var data = [{
    item: "Item 1",
    pages: 30,
    chapters: 3
},
{
    item: "Item 1",
    pages: 50,
    chapters: 3
},
{
    item: "Item 2",
    pages: 10,
    chapters: 3
}];

const processedData = data.reduce((items, { item, pages, chapters }) => {
    const ensureItemData = () =>
        items.find(itemData => itemData.item === item)
        ?? (() => {
            const itemData = { item, pages: 0, chapters: 0 };
            items.push(itemData);
            return itemData;
        })();

    const itemData = ensureItemData();
    itemData.pages += pages;
    itemData.chapters += chapters;

    return items;
}, []);

Upvotes: 2

Related Questions