0

I have an array of arrays with objects that looks like this:

var data = [
[{'name':'John', 'value':2},
{'name':'Randy', 'value':4}
],

[{'name':'Sarah', 'value':10},
{'name':'Julie', 'value':10}
]
];

I want to iterate through each array and add up values and store the totals in an array. What I came up with looks like this:

function add(accumulator, a) {
    return accumulator + a;
}

var totals = [];

var yExtent = data.forEach(function(item) {
  item.forEach(function(jtem) {
    var subTotals = [];
    subTotals.push(jtem.value);
    return subTotals;
  })
  var localTotal = subTotals.reduce(add,0);
  totals.push(localTotal);
  return totals;
});

console.log(totals)

However, this results in the error: "subTotals is not defined"

Question

Is this happening because subTotals is not in the same scope as the other part of the function? If so, how should I proceed? I cannot put var localTotal = subTotals.reduce(add,0); in scope because the forEach() would calculate it too frequently and give me the wrong values. How should I modify this code to return my inner forEach() calculations to the outer?

7
  • 2
    Except for a useless undefined, forEach doesn't return anything. Besides that, you have the scope issue of that variable. Commented May 17, 2019 at 1:21
  • 1
    move var subTotals = []; one line up out of the inner forEach Commented May 17, 2019 at 1:24
  • ^--- this, and also remove the return total (which is doing nothing anyway). Commented May 17, 2019 at 1:25
  • What is your expected output? Commented May 17, 2019 at 1:27
  • 1
    @ArashHowaida map + reduce. Commented May 17, 2019 at 1:29

4 Answers 4

2

forEach is for side effects. You really want to write your transforms using transforming functions instead of side effects. First, it will be shorter. Second, it will be clearer - you don't want a side effect, you want a pure transformation, and your code will reflect that. Using the same code, but with map instead results in this:

var totals = data.map(item => {
  var localTotal = item.map(datum => datum.value).reduce(add, 0);
  return localTotal;
});
Sign up to request clarification or add additional context in comments.

Comments

1

You might want to do something like

function selectValue(item) {
  return item.value;
}

const totals = data.map(
  subList => subList.map(selectValue)
                    .reduce(add, 0)
);

Comments

1

You need to move the declaration of subTotals outside of the forEach loop like this-

Also you shouldn't reuse item.

function add(accumulator, a) {
    return accumulator + a;
}

var totals = [];

var yExtent = data.forEach(function(item) {
    var subTotals = [];
    item.forEach(function(subItem) {
        var subs = [];
        subTotals.push(subItem.value);
        return subs;
    })
    var localTotal = subTotals.reduce(add,0);
    totals.push(localTotal);
    return totals;
});

console.log(totals)

This will still give you a multi-dimensional array so you may want to change the console log to console.log(totals.flat(2)).

Or you may want to add the numbers..

Comments

0

The array.forEach function is made so that it is impossible for it to return any value. There is not a way to over-ride this behavior. It's something they did under the hood. So, all you can do with .forEach is go through an array and do something with the items that are stored to the array, like console.log() them, etc.

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.