Home > Enterprise >  JavaScript: Recursive Countup Base Case
JavaScript: Recursive Countup Base Case

Time:12-17

I am currently doing a JavaScript exercise that requires me to create a recursive function that counts up from the starting number to the end number (inclusive). I have arrived at the solution, but I have been trying to make what I think is a synonymous base case to work, but I cannot get my head around it.

function rangeOfNumbers(startNum, endNum) {
  if (endNum < startNum) {
    return [];
  }
  const arr = rangeOfNumbers(startNum, endNum - 1);
  arr.push(endNum);
  return arr;
};

console.log(rangeOfNumbers(1, 5)) = [1, 2, 3, 4, 5]

The code above works, but the code below does not:

function rangeOfNumbers(startNum, endNum) {
  if (endNum = startNum) {
    return [endNum];
  }
  const arr = rangeOfNumbers(startNum, endNum - 1);
  arr.push(endNum);
  return arr;
};

console.log(rangeOfNumbers(1, 5)) = [1]

The latter only outputs an array with the startNum. I am confused at to why it is not computing the other stacks of the recursion, could someone explain this to me?

CodePudding user response:

The problem is you are using an assignment operator instead of an equality operator.

correct

if (endNum === startNum)

incorrect

if (endNum = startNum)

CodePudding user response:

The reason your second code block doesn't work is because of the if (endNum = startNum) line. By using the single equal sign, you're assigning startNum to endNum.

To check for equality, you'd use the equality operator (==) or the strict equality operator (===):

if (endNum === startNum) {
  return [endNum]
}

CodePudding user response:

Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutation, variable reassignments, and other side effects -

function rangeOfNumbers (startNum, endNum) {
  if (startNum > endNum)
    return []
  else
    return [startNum].concat(rangeOfNumbers(startNum   1, endNum))
}

console.log(JSON.stringify(rangeOfNumbers(0, 3)))
console.log(JSON.stringify(rangeOfNumbers(3, 7)))
console.log(JSON.stringify(rangeOfNumbers(9, 3)))

[0,1,2,3]
[3,4,5,6,7]
[]

Using functional style means you can substitute a function call for it's return value and always get the correct result. This gives you the ability to reason about your programs as though they are formulas or equations. It is simply not possible if you use recursion with imperative style -

rangeOfNumbers(3,6)
== [3].concat(rangeOfNumbers(4,6))
== [3].concat([4].concat(rangeOfNumbers(5,6)))
== [3].concat([4].concat([5].concat(rangeOfNumbers(6,6))))
== [3].concat([4].concat([5].concat([6].concat(rangeOfNumbers(7,6)))))
== [3].concat([4].concat([5].concat([6].concat([]))))
== [3].concat([4].concat([5].concat([6])))
== [3].concat([4].concat([5,6]))
== [3].concat([4,5,6])
== [3,4,5,6]

You can write the same thing as a pure functional expression -

const range = (start, end) =>
  start > end
    ? []
    : [start, ...range(start   1, end)]

console.log(JSON.stringify(range(0, 3)))
console.log(JSON.stringify(range(3, 7)))
console.log(JSON.stringify(range(9, 3)))

[0,1,2,3]
[3,4,5,6,7]
[]

This one can be visualized as -

range(3,6)
== [3, ...range(4, 6)]
== [3, ...[4, ...range(5, 6)]]
== [3, ...[4, ...[5, ...range(6, 6)]]]
== [3, ...[4, ...[5, ...[6, ...range(7, 6)]]]]
== [3, ...[4, ...[5, ...[6, ...[]]]]]
== [3, ...[4, ...[5, ...[6]]]]
== [3, ...[4, ...[5, 6]]]
== [3, ...[4, 5, 6]]
== [3, 4, 5, 6]

With just one more condition we can support inverse ranges too -

const range = (start, end) =>
  start > end
    ? range(end, start).reverse()
    : start == end
      ? [start]
      : [start, ...range(start   1, end)]

console.log(JSON.stringify(range(0, 3)))
console.log(JSON.stringify(range(3, 7)))
console.log(JSON.stringify(range(9, 3)))

[0,1,2,3]
[3,4,5,6,7]
[9,8,7,6,5,4,3]  // <- inverse

This last one can be visualized as -

range(9,6)
== range(6,9).reverse()
== [6, ...range(7,9)].reverse()
== [6, ...[7, ...range(8,9)]].reverse()
== [6, ...[7, ...[8, ...range(9,9)]]].reverse()
== [6, ...[7, ...[8, ...[9]]]].reverse()
== [6, ...[7, ...[8, 9]]].reverse()
== [6, ...[7, 8, 9]].reverse()
== [6, 7, 8, 9].reverse()
== [9, 8, 7, 6]
  • Related