1

Let's say I have an array of objects and want to group these by a specified key: 'name', and sum all of their values into one object:

[
  { 
    name: "test1",
    value1: 100,
    value2: 100,
    value3: 100
  },
  { 
    name: "test1",
    value1: 100,
    value2: 100,
    value3: 100
  },
  { 
    name: "test2",
    value1: 200,
    value2: 100,
    value3: 100
  },
  { 
    name: "test2",
    value1: 200,
    value2: 100,
    value3: 100
  }, 
  { 
    name: "test3",
    value1: 100,
    value2: 100,
    value3: 100
  }
]

And the result I want would have this structure:

[
  {
    name: "test1",
    value1: 200,
    value2: 200,
    value3: 200
  },
  { 
    name: "test2",
    value1: 400,
    value2: 200,
    value3: 200
  },
  {
    name: "test3",
    value1: 100,
    value2: 100,
    value3: 100
  }
]

How would I go about doing this? I can currently get the sum of one key by using this method:

  const total_sum_data = (arr, key, value) => {
    const map = new Map();
    for (const obj of arr) {
      const currSum = map.get(obj[key]) || 0;
      map.set(obj[key], currSum + obj[value]);
    }
    const res = Array.from(map, ([k, v]) => ({ [key]: k, [value]: v }));
    return res;
  };

But not sure how to merge the results into one object with the specified key.

4 Answers 4

1

You can reduce the array to an accumulator object (a) by destructuring each object into its name and values, and summing all the values for each name in the accumulator object. Then you just need to retrieve the accumulator's object values to get to your final result:

const result = Object.values(data.reduce((a, {name, ...values}) => {
  a[name] ??= { name };
  Object.entries(values).forEach(([key, value]) => {
    a[name][key] ??= 0;
    a[name][key] += value;
  });
  return a;
} , {}));

This solution has a time complexity of O(n). It will gracefully handle cases where new values are added (value4, value5, ...), and cases where not all values are present in all objects.


Complete snippet:

const data = [{
  name: "test1",
  value1: 100,
  value2: 100,
  value3: 100
}, {
  name: "test1",
  value1: 100,
  value2: 100,
  value3: 100
}, {
  name: "test2",
  value1: 200,
  value2: 100,
  value3: 100
}, {
  name: "test2",
  value1: 200,
  value2: 100,
  value3: 100
}, {
  name: "test3",
  value1: 100,
  value2: 100,
  value3: 100
}];

const result = Object.values(data.reduce((a, {name, ...values}) => {
  a[name] ??= { name };
  Object.entries(values).forEach(([key, value]) => {
    a[name][key] ??= 0;
    a[name][key] += value;
  });
  return a;
} , {}));

console.log(result);

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

2 Comments

I've never seen this syntax before: ??= nor can I find documentation on it, what is this doing? (also looks like webpack is unable to compile unless using a specific loader)
0

It can be achieved using Map and reduce.

while using Map here is a code:

const map = new Map();

for (const item of data) {
  if (!map.has(item.name)) {
    map.set(item.name, {
      name: item.name,
      value1: item.value1,
      value2: item.value2,
      value3: item.value3
    });
  } else {
    map.get(item.name).value1 += item.value1;
    map.get(item.name).value2 += item.value2;
    map.get(item.name).value3 += item.value3;
  }
}
console.log(Array.from(map.values()));

and while using reduce it can be done like this

const groupedSum = data.reduce((acc, curr) => {
  const objIndex = acc.findIndex(obj => obj.name === curr.name);
  if (objIndex === -1) {
    acc.push({ name: curr.name, value1: curr.value1, value2: curr.value2, value3: curr.value3 });
  } else {
    acc[objIndex].value1 += curr.value1;
    acc[objIndex].value2 += curr.value2;
    acc[objIndex].value3 += curr.value3;
  }
  return acc;
}, []);
console.log(groupedSum);

Comments

0

For example:

const total_sum_data = (arr, key) => {
  const map = new Map();
  for (const obj of arr) {
    const groupKey = obj[key];
    if (!map.has(groupKey)) {
      map.set(groupKey, { [key]: groupKey });
    }
    const currObj = map.get(groupKey);
    Object.keys(obj).forEach(k => {
      if (k !== key) {
        currObj[k] = (currObj[k] || 0) + obj[k];
      }
    });
  }
  return Array.from(map.values());
};

console.log(total_sum_data(arr,"name")); 

Comments

0

Hope below logic will help you

let array = [
  { 
    name: "test1",
    value1: 100,
    value2: 100,
    value3: 100
  },
  { 
    name: "test1",
    value1: 100,
    value2: 100,
    value3: 100
  },
  { 
    name: "test2",
    value1: 200,
    value2: 100,
    value3: 100
  },
  { 
    name: "test2",
    value1: 200,
    value2: 100,
    value3: 100
  }, 
  { 
    name: "test3",
    value1: 100,
    value2: 100,
    value3: 100
  },

]


let reduceArr = array.reduce((prev, next) =>{
    if (next.name in prev) {
      prev[next.name].value1 += next.value1;
      prev[next.name].value2 += next.value2;
      prev[next.name].value3 += next.value3;
    } else {
       prev[next.name] = next;
    }
    return prev;
  }, {});

let result = Object.values(reduceArr);


console.log(result)

1 Comment

Object.keys(reduceArr).map(id => reduceArr[id]); → Object.values(reduceArr);

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.