5

I need to group by id and sum, but I need a new object for each result:

let data = [
    {"id":"2018", "name":"test", "total":1200},
    {"id":"2019", "name":"wath", "total":1500},
    {"id":"2019", "name":"wath", "total":1800},
    {"id":"2020", "name":"zooi", "total":1000},
]

I have this code that returns just one object with the result

let result = data.reduce(function (r, o) {
    (r[o.id])?
        r[o.id] += o.total:
        r[o.id] = o.total;
    return r;
});

But I need some like this:

[
    {"id":"2018", "name":"test", "total":1200},
    {"id":"2019", "name":"wath", "total":2300},
    {"id":"2020", "name":"zooi", "total":1000},
]

How can I do it?

4 Answers 4

10

let data =[
    {"id":"2018", "name":"test", "total":1200},
    {"id":"2019", "name":"wath", "total":1500},
    {"id":"2019", "name":"wath", "total":1800},
    {"id":"2020", "name":"zooi", "total":1000},
];

let map = data.reduce((prev, next) =>{
  if (next.id in prev) {
    prev[next.id].total += next.total;
  } else {
     prev[next.id] = next;
  }
  return prev;
}, {});

let result = Object.keys(map).map(id => map[id]);

console.log(result);

Sign up to request clarification or add additional context in comments.

4 Comments

I don't see why you changed the code of the reduce. The only thing that mattered was Object.keys(map).map(id => map[id])
@ibrahimmahrir I did not understand what do you want to say. Is is bad?
@ZohaibIjaz No no. I meant to say that the reduce code change was irrelevant. Your answer could've been as short as saying, Do result = Object.keys(map).map(id => map[id]);, without having to rewrite reduce code.
@ibrahimmahrir No,that will not be correct answer. We need to group by id and sum total values. So reduce is required
5

You can try this:

const result = Object.values(data.reduce((r, o) => (r[o.id]
  ? (r[o.id].total += o.total)
  : (r[o.id] = {...o}), r), {}));

2 Comments

what does the '?' and the ':' mean?
@BreadBoard.ini it's known as the ternary operator. Basically it's an inline if-else condition. You can read more about it here developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
1

Change your reduce to:

let result = data.reduce(function(acc, obj) {             // for each obj in data
    if(acc.map.hasOwnProperty(obj.id)) {                  // if the map contains an object for the current object's id
        acc.map[obj.id].total += +obj.total;              // then add the current object's total to it
    } else {                                              // otherwise
        var newObj = Object.assign({}, obj);              // create a new object (a copy of the current object)
        acc.map[obj.id] = newObj;                         // add the new object to both the map
        acc.data.push(newObj);                            // ... and the data array
    }
    return acc;
}, {data: [], map: {}}).data;                             // the accumulator should have an array for the data objects (which will be our result) and a map object which maps the ids to the objects in the data array. Once our reduce finishes its work, we assign the data array of the accumulator to result

Example:

let data =[ {"id":"2018", "name":"test", "total":1200}, {"id":"2019", "name":"wath", "total":1500}, {"id":"2019", "name":"wath", "total":1800}, {"id":"2020", "name":"zooi", "total":1000} ];

let result = data.reduce(function(acc, obj) {
    if(acc.map.hasOwnProperty(obj.id)) {
        acc.map[obj.id].total += +obj.total;
    } else {
        var newObj = Object.assign({}, obj);
        acc.map[obj.id] = newObj;
        acc.data.push(newObj);
    }
    return acc;
}, {data: [], map: {}}).data;

console.log(result);

1 Comment

This really helped me thanks :) Very simple and detailed example
-1
import uniqBy from 'lodash/uniqBy'

export function transform (array) {
  const newArray = []
  const uniq = uniqBy(array, 'id')

  uniq.forEach(item => {
    const total = array
      .filter(({id}) => item.id === id)
      .reduce((sum, current) => sum + current.total, 0)

    newArray.push({
      ...item,
      total
    })
  })

  return newArray
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.