5

Let's say I have this:

function arrSum(){
  *code here*
}

How do I write the arrSum function such that it can sum all the integers within a multidimensional array (of variable depth).

I.e.

arrSum([2, 5, [4, 6], 5]) === 22;

I know there must be an answer to this somewhere but I really can't find it. If this is a duplicate please let me know.

Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
VoA
  • 503
  • 1
  • 6
  • 16
  • 1
    There is an anwser but using ES6: http://stackoverflow.com/a/33306533/5388620 It's almost the same answer as below and uses recursion too. – Shanoor Nov 12 '15 at 06:08

9 Answers9

8

Simply you can write a function like this with recursion

function arrSum(arr) {
  var sum = 0;
  // iterate array using forEach, better to use for loop since it have higher performance
  arr.forEach(function(v) {
    // checking array element is an array
    if (typeof v == 'object')
      // if array then getting sum it's element (recursion)
      sum += arrSum(v);
    else
      // else adding the value with sum
      sum += v
  })
  // returning the result
  return sum;
}

console.log(arrSum([2, 5, [4, 6], 5]) === 22);

Using for loop

function arrSum(arr) {
  var sum = 0;
  for (var i = 0; i < arr.length; i++) {
    if (typeof arr[i] == 'object')
      sum += arrSum(arr[i]);
    else
      sum += arr[i];
  }
  return sum;
}

console.log(arrSum([2, 5, [4, 6], 5]) === 22);
Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
  • This works perfectly - thank you. Can I just ask - why are you testing for typeof object? – VoA Nov 12 '15 at 06:08
  • @VoA : checking inner element is `array` or `number`, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof – Pranav C Balan Nov 12 '15 at 06:10
  • I would just move the **isObject** check before the `foreach`, that way, sending a single numeric, it will still work. – Tomer W Nov 12 '15 at 06:29
  • In your for loop answer you wrote: "sum += arrSum(arr[i]);". Could you explain what this is doing? Is it calling the arrSum function from within itself? – VoA Nov 12 '15 at 06:59
  • @VoA : calling the same function with inner array ( recursion ), and adding return value with `sum` variable – Pranav C Balan Nov 12 '15 at 07:03
5

A more modern approach using .reduce():

const arr = [2, 5, [4, 6], 5];

const arrSum = array =>
    array.reduce(
        (sum, num) => sum + (Array.isArray(num) ? arrSum(num) : num * 1),
        0
    );

console.log(arrSum(arr));
ryanpcmcquen
  • 6,285
  • 3
  • 24
  • 37
5

Why is no one using flat()?

const arr = [2, 5, [4, 6], 5];

const result = arr.flat().reduce((a,b) => a+b);

console.log(result);
zeh
  • 137
  • 1
  • 4
  • 12
1

Check this:

function arrSum(objArr){
  var total = 0;
  for(var outerLoop=0; outerLoop < objArr.length; outerLoop++){
    if(objArr[outerLoop].constructor === Array){
      for(var innerLoop=0; innerLoop < objArr[outerLoop].length; innerLoop++){
        total += objArr[outerLoop][innerLoop];
      }
    } else {
      total += objArr[outerLoop];
    }
  }
  return total;
}

alert (arrSum([2, 5, [4, 6], 5]));
Anshuman
  • 831
  • 5
  • 18
1
    function arrSum(arr) {
        var totalSum = null;
        var numString = arr.toString();
        var numberArray = numString.split(",");
        numberArray.forEach(function(ele){
          totalSum = totalSum + parseInt(ele);
        });
        return totalSum;
    }
    console.log(arrSum([2, 5, [4, 6], 5]);
DevDeb
  • 245
  • 3
  • 7
1

If we have a multi-dimensional array with strings and integers and we have to get the sum of the numbers, then following @Pranav C Balan's solution we could add a check in the else loop to check only for digits as below -

      function arrSum(arr) {
    var sum = 0;
    for (var i = 0; i < arr.length; i++) {
      if (typeof arr[i] == 'object'){
         sum += arrSum(arr[i]);
      }else if (Number(arr[i])){
         sum += arr[i];
      }
    }
    return sum;
  }
  console.log(arrSum([2, 'a', 5, [4, 6, 10, [1, 2, 'b'], 10], 5]));
0

I would build a function similar to what Pranav C Balan with the difference that i would check the isObject() before calling forEach(),
This way i get around problems posed by sending a single numeric parameter, or Null values.

function arrSum(v) {
  // checking if element is an array
  if (typeof v == 'object') {
    var sum = 0;
    
    // iterate array using forEach, better to use for loop since it have higher performance
    v.forEach(function(e) {
      sum+=arrSum(e);
    });
    return sum;
  }
  else {
      return v;
  }
}
$('body').append($('<p></p>').html('[2, 5, [4, 6], 5] = ' + arrSum([2, 5, [4, 6], 5])));
$('body').append($('<p></p>').html('[2,, 5] = ' + arrSum([2,, 5])));
$('body').append($('<p></p>').html('5 = ' + arrSum(5)));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Tomer W
  • 3,395
  • 2
  • 29
  • 44
0

This can be done with lodash _.flattenDeep and _.sum:

var arr = [2, 5, [4, 6], 5];
arrSum(arr);

function arrSum(arr) {
  var arrFlattens = _.flattenDeep(arr);
  // => [2, 5, 4, 6, 5]
  console.log(_.sum(arrFlattens));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
0

Expanding on @zeh's answer to include a check for number and convert a string to a number:

function arrSum(arr) {
  const sum = arr.flat().map(a => +a).filter(a => typeof a === "number" && !isNaN(a)).reduce((a,b) => a + b, 0);
  return sum;
}

Below is a breakdown of the code using an example 3D array - flat() depth set to 2.

const array3d  = [[2, '8', 5], [[4, 6], 10],[1, 2, 'b'],[10, 5, 'f']];

function arrSumBreakdown(arr) {
  // change any number strings to numbers
  const allnum   = arr.flat(2).map(a => +a);
  console.log('flat & convert to numbers: ',...allnum);
  // keep only numbers and remove NaN
  const numonly  = allnum.filter(a => typeof a === "number" && !isNaN(a));
  console.log('remove NaN:',...numonly);
  // sum array
  const sumnum   = numonly.reduce((a,b) => a + b, 0);
  return sumnum;
}

console.log('sum array:',arrSumBreakdown(array3d));

// all in one
function arrSum(arr) {
  const sum = arr.flat(2).map(a => +a).filter(a => typeof a === "number" && !isNaN(a)).reduce((a,b) => a + b, 0);
  return sum;
}

console.log('combine all elements (sum array):',arrSum(array3d));

references:

TopMarx
  • 77
  • 8