2

Why sum is undefined. What am I doing wrong?

var testData1 = [{
  "name": "Doctors",
  "category": "Doctors",
  "subCategory": [{
    "name": "Likes",
    "category": "Likes",
    "subCategory": [{
      "name": "Visit",
      "category": "Visit",
      "subCategory": [{
        "name": "Charges",
        "category": "Charges",
        "subCategory": null,
        "val": 30
      }]
    }]
  }, {
    "name": "Dislikes",
    "category": "Dislikes",
    "subCategory": [{
      "name": "Quality",
      "category": "Quality",
      "subCategory": [{
        "name": "Appointment",
        "category": "Appointment",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Care",
        "category": "Care",
        "subCategory": null,
        "val": 70
      }, {
        "name": "Attentive ",
        "category": "Attentive ",
        "subCategory": null,
        "val": 90
      }]
    }]
  }, {
    "name": "Neutral",
    "category": "Neutral",
    "subCategory": [{
      "name": "Professional ",
      "category": "Professional ",
      "subCategory": [{
        "name": "Ease",
        "category": "Ease",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Competent ",
        "category": "Competent ",
        "subCategory": null,
        "val": 40
      }, {
        "name": "Availability",
        "category": "Availability",
        "subCategory": null,
        "val": 80
      }]
    }]
  }],
  "index": 6
}, {
  "name": "Service",
  "category": "Service",
  "subCategory": [{
    "name": "Likes",
    "category": "Likes",
    "subCategory": [{
      "name": "Environment",
      "category": "Environment",
      "subCategory": [{
        "name": "Professionalism ",
        "category": "Professionalism ",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Room",
        "category": "Room",
        "subCategory": null,
        "val": 30
      }, {
        "name": "Parking",
        "category": "Parking",
        "subCategory": null,
        "val": 20
      }]
    }, {
      "name": "Availability",
      "category": "Availability",
      "subCategory": [{
        "name": "Competent ",
        "category": "Competent ",
        "subCategory": null,
        "val": 30
      }]
    }]
  }, {
    "name": "Dislikes",
    "category": "Dislikes",
    "subCategory": [{
      "name": "Management",
      "category": "Management",
      "subCategory": [{
        "name": "Staff",
        "category": "Staff",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Operations",
        "category": "Operations",
        "subCategory": null,
        "val": 70
      }]
    }, {
      "name": "Nurses",
      "category": "Nurses",
      "subCategory": [{
        "name": "Medicine",
        "category": "Medicine",
        "subCategory": null,
        "val": 30
      }]
    }]
  }, {
    "name": "Neutral",
    "category": "Neutral",
    "subCategory": [{
      "name": "Serving",
      "category": "Serving",
      "subCategory": [{
        "name": "Took long time",
        "category": "Took long time",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Rude",
        "category": "Rude",
        "subCategory": null,
        "val": 40
      }, {
        "name": "Seated",
        "category": "Seated",
        "subCategory": null,
        "val": 80
      }]
    }]
  }],
  "index": 16
}];

function addSum(data) {
  data.forEach(function(d, index) {
    if (Array.isArray(d.subCategory)) {
      return (0 + addSum(d.subCategory));

    } else {

      document.write('<pre>' + JSON.stringify(d.val, 0, 4) + '</pre>');
      return d.val;
    }
  });
}
var sum = addSum(testData1);
alert(sum);

0

4 Answers 4

4

Your return does not belong to addSum, it belongs to forEach, and that's why addSum returns nothing (undefined).
Array.prototype.forEach doesn't expect returning values, and cannot be used to calculate sum or something else.

You can utilize Array.prototype.reduce to achieve your result:

function sum(arr)
{
  return arr.reduce(function(a, b) { 
    return Array.isArray(b.subCategory) ? a + sum(b.subCategory) : a + b.val;
  }, 0);
}

sum(testData1);

Or using ECMAScript 6 arrow functions:

var sum = arr => arr.reduce((a, b) => Array.isArray(b.subCategory) 
    ? a + sum(b.subCategory) 
    : a + b.val, 0);

Working JSFiddle demo.

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

Comments

2

From .forEach you can't return value, that's why you get undefined, for this case more suitable .reduce method

function addSum(data) {
  return data.reduce(function (p, c) {
    return p + (Array.isArray(c.subCategory) ? addSum(c.subCategory) : c.val);
  }, 0);
}

Example

or if you want use .forEach you can do it like this

function addSum(data) {
  return function sum(data, result) {
    data.forEach(function (element) {
      result = Array.isArray(element.subCategory) 
        ? sum(element.subCategory, result)
        : result + element.val;
    });

    return result;
  }(data, 0);
}

Example

Comments

0

You can't return from your foreach, only from your function. Here's a working version of your function:

function addSum(data,tot) {
  tot = tot || 0;
  data.forEach(function(d, index) {
    if (Array.isArray(d.subCategory)) {
      tot = addSum(d.subCategory, tot);
    } else {
      tot += parseInt(d.val);
      document.write('<pre>' + d.val + ' - ' + tot + ' </pre>');
    }
  });
  return tot;
}

and a jsfiddle:

https://jsfiddle.net/mckinleymedia/uk5njxnp/

I agree that this should be simplified to a reduce function, but I thought it would also help to see how to modify what you did to make it work.

Comments

0

Return in the foreach function is for the callback and does not return from the addSum() function. Foreach callback return will not help in this case. Instead using some external variable for keeping the sum will do the trick.

The updated code below defines a variable sum inside the addSum() function and the return value of recursive call is added to it. The function will now return the calculated sum at the end.

var testData1 = [{
  "name": "Doctors",
  "category": "Doctors",
  "subCategory": [{
    "name": "Likes",
    "category": "Likes",
    "subCategory": [{
      "name": "Visit",
      "category": "Visit",
      "subCategory": [{
        "name": "Charges",
        "category": "Charges",
        "subCategory": null,
        "val": 30
      }]
    }]
  }, {
    "name": "Dislikes",
    "category": "Dislikes",
    "subCategory": [{
      "name": "Quality",
      "category": "Quality",
      "subCategory": [{
        "name": "Appointment",
        "category": "Appointment",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Care",
        "category": "Care",
        "subCategory": null,
        "val": 70
      }, {
        "name": "Attentive ",
        "category": "Attentive ",
        "subCategory": null,
        "val": 90
      }]
    }]
  }, {
    "name": "Neutral",
    "category": "Neutral",
    "subCategory": [{
      "name": "Professional ",
      "category": "Professional ",
      "subCategory": [{
        "name": "Ease",
        "category": "Ease",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Competent ",
        "category": "Competent ",
        "subCategory": null,
        "val": 40
      }, {
        "name": "Availability",
        "category": "Availability",
        "subCategory": null,
        "val": 80
      }]
    }]
  }],
  "index": 6
}, {
  "name": "Service",
  "category": "Service",
  "subCategory": [{
    "name": "Likes",
    "category": "Likes",
    "subCategory": [{
      "name": "Environment",
      "category": "Environment",
      "subCategory": [{
        "name": "Professionalism ",
        "category": "Professionalism ",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Room",
        "category": "Room",
        "subCategory": null,
        "val": 30
      }, {
        "name": "Parking",
        "category": "Parking",
        "subCategory": null,
        "val": 20
      }]
    }, {
      "name": "Availability",
      "category": "Availability",
      "subCategory": [{
        "name": "Competent ",
        "category": "Competent ",
        "subCategory": null,
        "val": 30
      }]
    }]
  }, {
    "name": "Dislikes",
    "category": "Dislikes",
    "subCategory": [{
      "name": "Management",
      "category": "Management",
      "subCategory": [{
        "name": "Staff",
        "category": "Staff",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Operations",
        "category": "Operations",
        "subCategory": null,
        "val": 70
      }]
    }, {
      "name": "Nurses",
      "category": "Nurses",
      "subCategory": [{
        "name": "Medicine",
        "category": "Medicine",
        "subCategory": null,
        "val": 30
      }]
    }]
  }, {
    "name": "Neutral",
    "category": "Neutral",
    "subCategory": [{
      "name": "Serving",
      "category": "Serving",
      "subCategory": [{
        "name": "Took long time",
        "category": "Took long time",
        "subCategory": null,
        "val": 50
      }, {
        "name": "Rude",
        "category": "Rude",
        "subCategory": null,
        "val": 40
      }, {
        "name": "Seated",
        "category": "Seated",
        "subCategory": null,
        "val": 80
      }]
    }]
  }],
  "index": 16
}];

function addSum(data) {
   sum = 0; 
  data.forEach(function(d, index) {
    if (Array.isArray(d.subCategory)) {
      sum += (0 + addSum(d.subCategory));

    } else {

      document.write('<pre>' + JSON.stringify(d.val, 0, 4) + '</pre>');
      sum += d.val;
    }
  });

  return sum;
}
var sum1 = addSum(testData1);
alert(sum1);

Comments

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.