Praz Solver
Praz Solver

Reputation: 543

Sum the properties of array of object types and join them as single object

Need to sum the score and total_score of distinct objects based on subject names property.

Input data :

var data = [{
  name: "One",
  maths: {
    score: 2,
    total_score: 4
  },
  science: {
    score: 2,
    total_score: 4
  },
  social: {
    score: 2,
    total_score: 4
  }
}, {
  name: "One",
  maths: {
    score: 3,
    total_score: 4
  },
  science: {
    score: 1,
    total_score: 4
  },
  english: {
    score: 4,
    total_score: 4
  }
}]

Expected Output :

{
  name: "One",
  maths: {
    score: 5,
    total_score: 8
  },
  science: {
    score: 3,
    total_score: 8
  },
  social: {
    score: 2,
    total_score: 4
  },
  english: {
    score: 4,
    total_score: 4
  }
}

I have tried this :

data.forEach(function (a) {
    if (!this[a.name]) {
        this[a.name] = { name: a.name, contributions: 0 };
        result.push(this[a.name]);
    }
    this[a.name].contributions += a.contributions;
}, Object.create(null));

But it does not work for my case. Where the contributions object is different i.e Subject names are different each time.

Thanks in advance folks!

Upvotes: 0

Views: 192

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386654

You could take an array as temporary result for reducing and look for the object with the same name and update all futher properties.

var data = [{ name: "One", maths: { score: 2, total_score: 4 }, science: { score: 2, total_score: 4 }, social: { score: 2, total_score: 4 } }, { name: "One", maths: { score: 3, total_score: 4 }, science: { score: 1, total_score: 4 }, english: { score: 4, total_score: 4 } }],
    result = data.reduce((r, o) => {
        var temp = r.find(({ name }) => name === o.name);
        if (!temp) {
            r.push(temp = { name: o.name });
        }
        Object.entries(o).forEach(([k, p]) => {
            if (k === 'name') return;
            temp[k] = temp[k] || {};
            ['score', 'total_score'].forEach(l => temp[k][l] = (temp[k][l] || 0) + o[k][l]);
        });
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Ankit Agarwal
Ankit Agarwal

Reputation: 30739

You can use Array.reduce():

var data = [{
    name: "One",
    maths: {
      score: 2,
      total_score: 4
    },
    science: {
      score: 2,
      total_score: 4
    },
    social: {
      score: 2,
      total_score: 4
    }
  },
  {
    name: "One",
    maths: {
      score: 3,
      total_score: 4
    },
    science: {
      score: 1,
      total_score: 4
    },
    english: {
      score: 4,
      total_score: 4
    }
  },
  {
    name: "Two",
    maths: {
      score: 3,
      total_score: 4
    },
    science: {
      score: 1,
      total_score: 4
    },
    english: {
      score: 4,
      total_score: 4
    }
  },
  {
    name: "Two",
    maths: {
      score: 3,
      total_score: 5
    },
    science: {
      score: 1,
      total_score: 5
    },
    english: {
      score: 4,
      total_score: 6
    }
  }
];
var res = data.reduce((acc, item)=>{
  var exist = acc.find(({name}) => name === item.name);
  if(exist){
    Object.keys(item).forEach((key) =>{
      if(key !== 'name'){
        if(exist[key]){
          exist[key].total_score += item[key].total_score;
          exist[key].score += item[key].score
        } else {
           exist[key] = item[key]
        }
      }
    });
  } else {
    acc.push(item);
  }
  return acc;
}, []);
console.log(res);

Upvotes: 1

Nikhil Aggarwal
Nikhil Aggarwal

Reputation: 28455

Try following

  • Convert the array into an object using Array.reduce with key as name and value as resulting object. And then use Object.values to collect all the values from the created object
  • While creating object, check if key (name) exists in object. If not, add an entry for it (a[name] = a[name] || {name};).
  • Now for all the other keys (subjects), create an array using Object.entries and iterate over it to add/update the values of score and total_score.

var data = [{name: "One", maths: {score: 2, total_score: 4}, science: {score: 2, total_score: 4}, social: {score: 2, total_score: 4}},{name: "One", maths: {score: 3, total_score: 4}, science: {score: 1, total_score: 4}, english: {score: 4, total_score: 4}}];
var result = Object.values(data.reduce((a,{name, ...rest}) => {
  a[name] = a[name] || {name};
  Object.entries(rest).forEach(([k,v]) => {
    a[name][k] = a[name][k] || {score:0, total_score:0};
    a[name][k].score += v.score;
    a[name][k].total_score += v.total_score;
  });
  return a;
},{}));
console.log(result);

Upvotes: 1

Related Questions