SBP
SBP

Reputation: 147

Object array based on two object array calculations in Javascript

I have to do some calcucations based on inputArray and factorArray and create third array outputArray. You can see caclucations part in outputArray properties marks and noOfStudents based on the subject property

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' }
];

var factorArray = [
  { subject: 'History', marks: '500', noOfStudents: '200' },
  { subject: 'Maths', marks: '200', noOfStudents: '150' },
  { subject: 'Science', marks: '300', noOfStudents: '100' }      
];

var outputArray = [
    { subject: 'Science', marks: '300-(50+65)', noOfStudents: '100-(16+2)' },
    { subject: 'Maths', marks: '200-(40+30)', noOfStudents: '150-(5+12)' },
    { subject: 'History', marks: '500-(35+55)', noOfStudents: '200-(23+20)' }
 ];

I need to extend the solution to my previous question: https://stackoverflow.com/a/37481705

Upvotes: 0

Views: 72

Answers (3)

Redu
Redu

Reputation: 26161

I would prefer doing by cascaded reduces like

var inar = [{ 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' }],
   facar = [{ subject: 'History', marks: '500', noOfStudents: '200' },{ subject: 'Maths', marks: '200', noOfStudents: '150' },{ subject: 'Science', marks: '300', noOfStudents: '100' }];

   outar = inar.reduce((p,c) => {var f = p.find(o => o.subject === c.subject);
                                 f ? (f.marks = f.marks*1 + c.marks*1,
                                      f.noOfStudents = f.noOfStudents*1 + c.noOfStudents*1)
                                   : p.push(c);
  	                         return p},[])
               .reduce((p,c) => {var f = p.find(o => o.subject === c.subject);
                                 f.marks = f.marks*1 - c.marks*1;
                                 f.noOfStudents = f.noOfStudents*1 - c.noOfStudents*1;
                                 return p},facar);
console.log(outar);

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386654

This proposal uses a temp object, first for the result of the grouping of inputArray and later for the creation of outputArray. The complexity of this operation is linear O(n+m).

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' }],
    factorArray = [{ subject: 'History', marks: '500', noOfStudents: '200' }, { subject: 'Maths', marks: '200', noOfStudents: '150' }, { subject: 'Science', marks: '300', noOfStudents: '100' }],
    temp = Object.create(null),
    outputArray = [];

inputArray.forEach(function (a) {
    this[a.subject] = this[a.subject] || { marks: [], noOfStudents: [] };
    this[a.subject].marks.push(a.marks);
    this[a.subject].noOfStudents.push(a.noOfStudents);
}, temp);

outputArray = factorArray.map(function (a) {
    var getSum = function (k) {
        return this[a.subject] && this[a.subject][k].length ? '-(' + this[a.subject][k].join('+') + ')' : '';
    }.bind(this);
    return { subject: a.subject, marks: a.marks + getSum('marks'), noOfStudents: a.noOfStudents + getSum('noOfStudents') };
}, temp);

console.log(outputArray);

Result with calculated items

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' }],
    factorArray = [{ subject: 'History', marks: '500', noOfStudents: '200' }, { subject: 'Maths', marks: '200', noOfStudents: '150' }, { subject: 'Science', marks: '300', noOfStudents: '100' }],
    temp = Object.create(null),
    outputArray = [];

inputArray.forEach(function (a) {
    this[a.subject] = this[a.subject] || { marks: 0, noOfStudents: 0 };
    this[a.subject].marks += +a.marks;
    this[a.subject].noOfStudents += +a.noOfStudents;
}, temp);

outputArray = factorArray.map(function (a) {
    var getSum = function (k) {
        return (+a[k] - (this[a.subject] && this[a.subject][k] || 0)).toString();
    }.bind(this);
    return { subject: a.subject, marks: getSum('marks'), noOfStudents: getSum('noOfStudents') };
}, temp);

console.log(outputArray);

Upvotes: 1

IMTheNachoMan
IMTheNachoMan

Reputation: 5821

If subject in factorArray is unique:

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' }
];

var factorArray = [
  { subject: 'History', marks: '500', noOfStudents: '200' },
  { subject: 'Maths', marks: '200', noOfStudents: '150' },
  { subject: 'Science', marks: '300', noOfStudents: '100' }      
];

// the result
var outputArray = [];

// loop through the factors
for(var i = 0, numFactors = factorArray.length; i < numFactors; ++i) {
  // this iteration
  var thisFactor = factorArray[i];
  
  // make a copy
  var thisOutput = {
    "subject" : thisFactor.subject,
    "marks" : thisFactor.marks,
    "noOfStudents" : thisFactor.noOfStudents
  };
  
  // loop through the input
  for(var j = 0; j < inputArray.length; ++j) {
    // this iteration
    var thisInput = inputArray[j];
    
    // if the subject matches
    if(thisInput.subject == thisOutput.subject) {
      // do the calculation
      thisOutput.marks -= thisInput.marks;
      thisOutput.noOfStudents -= thisInput.noOfStudents;
      
      // we don't need to loop through this one again so remove it from the inputArray
      // and decrease j so we check it again on the "next" iteration
      inputArray.splice(j--, 1);
    }
  }
  
  // save it
  outputArray.push(thisOutput);
}

console.log(outputArray);

Upvotes: 0

Related Questions