JavaScript Recursive function not returning sum of object values recursive function returning none,recursive function returning undefined,recursive function

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);
Answer:1

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.

Answer: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

Answer:3

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.

Answer:4

I currently have three nested promises which I want to turn into a $q.all call. It looks something like this. ds.saveData(data).then(function (result1){ someOtherVar = result1.Id; ds....

I currently have three nested promises which I want to turn into a $q.all call. It looks something like this. ds.saveData(data).then(function (result1){ someOtherVar = result1.Id; ds....

I'm trying to make a tooltip using jQuery, with HTML and CSS. Each tooltip is different by the id and that works great, so I can make as many tooltips as I want and style them independently. What I ...

I'm trying to make a tooltip using jQuery, with HTML and CSS. Each tooltip is different by the id and that works great, so I can make as many tooltips as I want and style them independently. What I ...

This is my first question on Stackoverflow so please excuse any mistakes I make. I'm trying to display in the view, some HTML from a template, which I use in the following directive: app.directive('...

This is my first question on Stackoverflow so please excuse any mistakes I make. I'm trying to display in the view, some HTML from a template, which I use in the following directive: app.directive('...

  1. html user insert image

I'm trying to open a remote video (let's say it's located at http://www.example.com/video.mp4) with the default Android player launched directly from Google Chrome, making use of the brand new intent:/...

I'm trying to open a remote video (let's say it's located at http://www.example.com/video.mp4) with the default Android player launched directly from Google Chrome, making use of the brand new intent:/...

  1. open video react native