-1

I have an array of objects where i need sum of object property values in new array of objects,

Input:

var inputArray = [
  { subject: 'Maths', marks: '40', noOfStudents: '5' },
  { subject: 'Science', marks: '50', noOfStudents: '16' },
  { subject: 'History', marks: '35', noOfStudents: '23' },
  { subject: 'Science', marks: '65', noOfStudents: '2' },
  { subject: 'Maths', marks: '30', noOfStudents: '12' },
  { subject: 'History', marks: '55', noOfStudents: '20' },
  .
  .
  .
];

Output i need,

var outputArray = [
  { subject: 'Maths', marks: '70', noOfStudents: '17' },
  { subject: 'Science', marks: '115', noOfStudents: '18' },
  { subject: 'History', marks: '95', noOfStudents: '43' },
  .
  .
  .
];

I want sum of marks and no of students of subjects in new object array. There would be N number of other subject objects (i.e-Geography, Physics etc) in the input array.

SBP
  • 147
  • 1
  • 6
  • 1
    Welcome to Stack Overflow! Your question should show what you've tried so far, and what exactly is the problem you're facing. – Schlaus May 27 '16 at 10:55
  • [`var result = []; inputArray.forEach(function(obj) { var existingObj = result.find(e => e.subject === obj.subject); if (existingObj) { existingObj.marks = +existingObj.marks + +obj.marks; existingObj.noOfStudents = +existingObj.noOfStudents + +obj.noOfStudents; } else { result.push(obj); } });`](https://jsfiddle.net/tusharj/5s7o9xzk/) – Tushar May 27 '16 at 11:00
  • @Tushar : using your code , the original object will get updated – Pranav C Balan May 27 '16 at 11:15
  • @Tushar : https://jsfiddle.net/5s7o9xzk/1/ – Pranav C Balan May 27 '16 at 11:23

6 Answers6

2

Simple reduce solution :

const data = [
  { subject: 'Maths', marks: '40', noOfStudents: '5' },
  { subject: 'Science', marks: '50', noOfStudents: '16' },
  { subject: 'History', marks: '35', noOfStudents: '23' },
  { subject: 'Science', marks: '65', noOfStudents: '2' },
  { subject: 'Maths', marks: '30', noOfStudents: '12' },
  { subject: 'History', marks: '55', noOfStudents: '20' }];

const result = data.reduce((cur, val) => {
  let alreadyIn = cur.find(e => e['subject'] == val['subject']);
  if (alreadyIn) {
    alreadyIn['marks'] = (parseInt(alreadyIn['marks']) + parseInt(val['marks'])).toString();
    alreadyIn['noOfStudents'] = (parseInt(alreadyIn['noOfStudents']) + parseInt(val['noOfStudents'])).toString();
  } else {
    cur.push(val);
  }
  return cur;
}, []);

console.log(result);
h0ly
  • 161
  • 1
  • 8
1

You can use forEach() to iterate and generate the new array

var inputArray = [
  { subject: 'Maths', marks: '40', noOfStudents: '5' },
  { subject: 'Science', marks: '50', noOfStudents: '16' },
  { subject: 'History', marks: '35', noOfStudents: '23' },
  { subject: 'Science', marks: '65', noOfStudents: '2' },
  { subject: 'Maths', marks: '30', noOfStudents: '12' },
  { subject: 'History', marks: '55', noOfStudents: '20' }
],
    res = [],
    key = {};

inputArray.forEach(function(v) {
  if (key.hasOwnProperty(v.subject)) { // check subject already added by using key object
    res[key[v.subject]].marks += Number(v.marks); //incase already exist parse number and add
    res[key[v.subject]].noOfStudents += Number(v.noOfStudents);
  } else {
    key[v.subject] = res.length; // create index entry in key object
    res.push({ // push the value 
      'subject': v.subject,
      'marks': Number(v.marks),
      'noOfStudents': Number(v.noOfStudents)
    })
    // if you pushed the original object then the original array also will get updated while adding the mark, so never push the refernce
  }
})

console.log(res);

Using reduce() method

var inputArray = [
  { subject: 'Maths', marks: '40', noOfStudents: '5' },
  { subject: 'Science', marks: '50', noOfStudents: '16' },
  { subject: 'History', marks: '35', noOfStudents: '23' },
  { subject: 'Science', marks: '65', noOfStudents: '2' },
  { subject: 'Maths', marks: '30', noOfStudents: '12' },
  { subject: 'History', marks: '55', noOfStudents: '20' }
],
    key = {};

res=inputArray.reduce(function(arr,v) {
  if (key.hasOwnProperty(v.subject)) { // check subject already added by using key object
    arr[key[v.subject]].marks += Number(v.marks); //incase already exist parse number and add
    arr[key[v.subject]].noOfStudents += Number(v.noOfStudents);
  } else {
    key[v.subject] = arr.length; // create index entry in key object
    arr.push({ // push the value 
      'subject': v.subject,
      'marks': Number(v.marks),
      'noOfStudents': Number(v.noOfStudents)
    })
    // if you pushed the original object then the original array also will get updated while adding the mark, so never push the refernce     
  }
  return arr;
},[])

console.log(res);

FYI : You can avoid the key object by using find() method, but performance wise that may be little bit slower.

Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
0

You can do this with forEach and thisArg optional parameter

var inputArray = [
  { subject: 'Maths', marks: '40', noOfStudents: '5' },
  { subject: 'Science', marks: '50', noOfStudents: '16' },
  { subject: 'History', marks: '35', noOfStudents: '23' },
  { subject: 'Science', marks: '65', noOfStudents: '2' },
  { subject: 'Maths', marks: '30', noOfStudents: '12' },
  { subject: 'History', marks: '55', noOfStudents: '20' },
], outputArray = [];
  
inputArray.forEach(function(e) {
  if(!this[e.subject]) {
    this[e.subject] = { subject: e.subject, marks:  0, noOfStudents: 0 }
     outputArray.push(this[e.subject]);
   }
  this[e.subject].marks += Number(e.marks);
  this[e.subject].noOfStudents += Number(e.noOfStudents);
}, {});

console.log(outputArray)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • Thanks Nenad, that is wanted. One more thing i want here, i have one more exactly similar array like inputArray. That is factorArray. calculation is like outputArrayObject.marks = factorArrayObject.marks - (sum of marks you did currently) – SBP May 27 '16 at 11:41
  • Well you can do this but it will work if your object in factorArray are in same order as objects in outputArray https://jsfiddle.net/Lg0wyt9u/913/ else you need to sort them. – Nenad Vracar May 27 '16 at 12:16
  • factorArray objects order is not same as outputArray and also objects in factorArray count would be more or less as compared to outputArray – SBP May 27 '16 at 12:26
0

Here you go:

function convert(inputArray) {
    var temp = {};
    for(var i = 0; i < inputArray.length; i++) {
        var subject = inputArray[i].subject;

        // check if there is already an entry with this subject in the temp array
        if(temp.hasOwnProperty(subject)) {
            // if it is already in the list, add the marks and the noOfStudents
            temp[subject].marks = temp[subject].marks + parseInt(inputArray[i].marks, 10);
            temp[subject].noOfStudents = temp[subject].noOfStudents + parseInt(inputArray[i].noOfStudents, 10);
        }
        else {
            // if it is not yet in the list, add a new object
            temp[subject] = {
                subject: subject,
                marks: parseInt(inputArray[i].marks, 10),
                noOfStudents: parseInt(inputArray[i].noOfStudents, 10)
            }
        }
    }

    // the temporary array is based on the subject, you are however interested on the effective value object
    var result = [];
    for(var entryKey in temp) {
        result.push(temp[entryKey]);
    }

    return result;
}
ssc-hrep3
  • 15,024
  • 7
  • 48
  • 87
0

The solution using Array.forEach, parseInt and Object.keys functions:

var summed = {}, result;
inputArray.forEach(function (obj) {
    obj['marks'] = parseInt(obj['marks']);
    obj['noOfStudents'] = parseInt(obj['noOfStudents']);
    var subj = obj['subject'];

    if (!summed[subj]) {
        summed[subj] = obj;
    } else {
        summed[subj]['marks'] += obj['marks'];
        summed[subj]['noOfStudents'] += obj['noOfStudents'];
    }
}, summed);
result = Object.keys(summed).map((k) => summed[k]);

console.log(JSON.stringify(result, 0, 4));

The output:

[
    {
        "subject": "Maths",
        "marks": 70,
        "noOfStudents": 17
    },
    {
        "subject": "Science",
        "marks": 115,
        "noOfStudents": 18
    },
    {
        "subject": "History",
        "marks": 90,
        "noOfStudents": 43
    }
]
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
0

Just another proposal with an object as hashtable.

var inputArray = [{ subject: 'Maths', marks: '40', noOfStudents: '5' }, { subject: 'Science', marks: '50', noOfStudents: '16' }, { subject: 'History', marks: '35', noOfStudents: '23' }, { subject: 'Science', marks: '65', noOfStudents: '2' }, { subject: 'Maths', marks: '30', noOfStudents: '12' }, { subject: 'History', marks: '55', noOfStudents: '20' }],
    outputArray = [];
inputArray.forEach(function (a) {
    if (!this[a.subject]) {
        this[a.subject] = { subject: 'Maths', marks: '0', noOfStudents: '0' };
        outputArray.push(this[a.subject]);
    }
    this[a.subject].marks = (+this[a.subject].marks + +a.marks).toString();
    this[a.subject].noOfStudents = (+this[a.subject].noOfStudents + +a.noOfStudents).toString();
}, Object.create(null));

console.log(outputArray);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392