11

Looking for a way to solve this problem by recursing sum(). Right now, the code works, but I am supposed to call sum() more than once, and it should not mutate the input array.

var sum = function(array) {
    if(array.length === 0){
        return 0;
    }
    function add(array, i){
        console.log(array[i]);
        if(i === array.length-1){
            return array[i];
        }
        return array[i] + add(array, i+1);
    }
    return add(array, 0);
};
sum([1, 2, 3, 4, 5, 6]) //21
4
  • 1
    I believe what you (they) are looking for is function sum(array) { return array.length ? array[0] + sum(array.slice(1)) : 0; } Commented May 24, 2016 at 23:49
  • @Bergi that's a possible answer, but I don't believe a good answer should be taking copies of any part of the array Commented May 24, 2016 at 23:56
  • @Alnitak Why? It's not a requirement stated by the OP. It's a fairly basic problem designed to help the OP's understanding of recursion. Seeking the most efficient solution misses the point - compactness and clarity should be a better goal in this case. Commented May 25, 2016 at 0:03
  • @Alnitak: I think it's better (purer) than giving sum an extra optional parameter :-) Commented May 25, 2016 at 0:20

8 Answers 8

36

A one-liner that meets all your requirements:

var sum = function(array) {
    return (array.length === 0) ? 0 : array[0] + sum(array.slice(1));
}

// or in ES6

var sum = (array) => (array.length === 0) ? 0 : array[0] + sum(array.slice(1));

// Test cases
sum([1,2,3]); // 6

var s = [1,2,3];
sum(s); // 6
sum(s); // 6

Reasoning

  • In a recursive call, you need to model your task as reduction to a base case. The simplest base case in this case is the empty array - at that point, your function should return zero.
  • What should the reduction step be? Well you can model a sum of an array as the result of adding the first element to the sum of the remainder of the array - at some point, these successive calls will eventually result in a call to sum([]), the answer to which you already know. That is exactly what the code above does.
  • array.slice(1) creates a shallow copy of the array starting from the first element onwards, and no mutation ever occurs on the original array. For conciseness, I have used a ternary expression.

Breakdown:

sum([1,2,3])
-> 1 + sum([2,3])
-> 1 + 2 + sum([3])
-> 1 + 2 + 3 + sum([])
-> 1 + 2 + 3 + 0
-> 6
Sign up to request clarification or add additional context in comments.

Comments

3

You're on the right track, but consider that sum could take an optional second argument (that defaults to zero) that indicates the position to start summing from...

function sum(array, n) {
    n ||= 0;
    if (n === array.length) {
        return 0;
    } else {
        return array[n] + sum(array, n + 1);
    }
}

4 Comments

What is n ||= 0; doing? Is it short for n = n || 0 ?
@kidwon yes - alternatively use if (n === undefined) n = 0;
is n || = 0 ES6? It's so useful
This is mixing of concerns. Your function is less reusable. sum should just do what it claims to do, namely adding something up. If you want to skip the first x elements, just slice the array before passing it to sum.
1
function sumArr(arr){
  if(arr.length>1){
    return arr.pop()+sumArr(arr);
  }else{
    return arr[0];
  }
}

Comments

1

function sumNumbersRecursively(input){
    if (input.length == 0){
        return 0;
    } else{
       return input.shift() + sumNumbersRecursively(input);
    }
}

console.log(sumNumbersRecursively([2,3,4]))

1 Comment

What advantage does that have over the accepted answer? I see a significant disadvantage in that it destroys the array you're trying to sum.
0

You don't really need the add function inside your sum function just inline the function and initiate with, 0 as a starting point, or optionally check the i variable for undefined and initialize it to 0!

var sum = function(array, i) {
    if(array.length === 0){
        return 0;
    }
  console.log(array[i]);
  if(i === array.length-1){
    return array[i];
  }
  return array[i] + sum(array, i+1);
};
console.log(sum([1, 2, 3, 4, 5, 6],0)) //21

Comments

0

You have two solutions:

  • you can use .reduce() method
  • or perform a simple tail recursion

With reduction:

function sum(a, b) {
  return a + b;
}

const array = [1, 2, 3, 4, 5, 6];

//In our reduce, we will apply our sum function, 
//and pass the result as the next value
const res = array.reduce(sum);

With recursion:

function sumRec(array, acc = 0, index) {
    //We will update our accumulator, and increment
  // the value of our current index
  return index === array.length
  ? acc
  : sumRec(array, acc += array[index], ++index);
}

console.log(sumRec(array, 0, 0));

Personally, I find the first solution more elegant.

1 Comment

the first solution is indeed elegant, but it's not the recursion that the OP has been asked for.
0

arr = [1,2,3,4]
sum = arr.reduce((acc, curr)=> acc+curr)

1 Comment

This doesn't use recursion which the OP has asked for
-1

If you have to call sum more than once, then use the binary approach: split the array in half and recur on each piece. When you get to a length of 1, return the single value.

Does this work for you? I'm afraid I don't recall the JS syntax for array slices, so my recursion statement may be wrong in the details.

var sum = function(array) {
    if(array.length === 1){
        return array[0];
    }
    mid = array.length / 2
    return sum(array[0:mid-1]) + sum(array[mid:array.length-1])
};
sum([1, 2, 3, 4, 5, 6]) //21

3 Comments

there is no advantage to a binary approach - the number of recursive calls and additions is still O(n).
also taking array slices means that the program uses a lot more memory than required
The advantage is that OP has a requirement to call sum more than once. That's the only reason I used the binary approach. Otherwise, taking advantage would require multi-threading, which would only bear fruit with very large arrays.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.