skip to Main Content

I have an array of objects, where I want to find the objects having same value for name property and then merge them into single object by adding their values & subvalues.

const arr = [
 { id: 1, name: 'a', value: 2, subvalue: 3 }, 
 { id: 2, name: 'b', value: 4, subvalue: 3 },
 { id: 3, name: 'c', value: 4, subvalue: 3 },
 { id: 4, name: 'b', value: 3, subvalue: 4 } 
]

Expected output

[
 { id: 1, name: 'a', value: 2, subvalue: 3 }, 
 { id: 2, name: 'b', value: 7, subvalue: 7 },
 { id: 3, name: 'c', value: 4, subvalue: 3 }
]

The id of the new object can either be 2 or it can be 4. So it doesn’t matter much. I have tried using filter, but not able to find a solution which suits my requirement

2

Answers


  1. Using only Array#reduce, see if the name of the current object is already present in the accumulator with Array#findIndex, then Values and Subvalues should be accumulated respectively with the current object Values and Subvalues, Otherwise add the current object in the accumulator:

    const arr = [ { id: 1, name: 'a', value: 2, subvalue: 3 }, { id: 2, name: 'b', value: 4, subvalue: 3 }, { id: 3, name: 'c', value: 4, subvalue: 3 }, { id: 4, name: 'b', value: 3, subvalue: 4 } ];
    const result = arr.reduce((acc, cur) => {
      const index = acc.findIndex((obj) => obj.name === cur.name);
      if (index !== -1) {
        acc[index] = {
          ...acc[index],
          value: acc[index].value + cur.value,
          subvalue: acc[index].subvalue + cur.subvalue,
        };
      } else {
        acc.push(cur);
      }
      return acc;
    }, []);
    console.log(result);

    if you don’t want to maintain the first (original) id and would rather use the id from the last (most recent) merged object, just replace ...acc[index] with ...cur when you merge them.

    Login or Signup to reply.
  2. you can use reduce to group by name and then get the values array of the grouped object using Object.values

    const arr = [
     { id: 1, name: 'a', value: 2, subvalue: 3 }, 
     { id: 2, name: 'b', value: 4, subvalue: 3 },
     { id: 3, name: 'c', value: 4, subvalue: 3 },
     { id: 4, name: 'b', value: 3, subvalue: 4 } 
    ]
    
    const res = Object.values(arr.reduce((acc,curr) => {
      if(!acc[curr.name]){
        acc[curr.name] = curr
      } else {
        acc[curr.name].value += curr.value
        acc[curr.name].subvalue += curr.subvalue
      }
      return acc
    },{}))
    
    console.log(res)

    or the whole if else logic be one-lined but less readable

    const arr = [
     { id: 1, name: 'a', value: 2, subvalue: 3 }, 
     { id: 2, name: 'b', value: 4, subvalue: 3 },
     { id: 3, name: 'c', value: 4, subvalue: 3 },
     { id: 4, name: 'b', value: 3, subvalue: 4 } 
    ]
    
    const res = Object.values(arr.reduce((acc, curr) => {
        acc[curr.name] = acc[curr.name] ? {...acc[curr.name], value: acc[curr.name].value + curr.value, subvalue: acc[curr.name].subvalue + curr.subvalue} : curr
        return acc
    }, {}))
    
    console.log(res)
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search