【问题标题】:JavaScript: Recursive Countup Base CaseJavaScript:递归计数基本案例
【发布时间】:2022-01-19 22:11:09
【问题描述】:

我目前正在做一个 JavaScript 练习,要求我创建一个递归函数,该函数从开始数到结束数(包括)进行计数。我已经找到了解决方案,但我一直在尝试使我认为是同义的基本案例起作用,但我无法理解它。

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]

上面的代码有效,但下面的代码无效:

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]

后者仅输出带有startNum 的数组。我很困惑为什么它不计算递归的其他堆栈,有人可以向我解释一下吗?

【问题讨论】:

    标签: javascript recursion


    【解决方案1】:

    递归是一种函数式遗产,因此将其与函数式风格一起使用会产生最佳效果。这意味着要避免诸如突变、变量重新分配和其他副作用之类的事情 -

    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]
    []
    

    使用函数样式意味着您可以将函数调用替换为 return 值,并且总是得到正确的结果。这使您能够对程序进行推理,就好像它们是公式或equations。如果您使用具有命令式风格的递归,那根本不可能 -

    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]
    

    你可以写出和纯函数表达式一样的东西——

    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]
    []
    

    这个可以可视化为-

    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]
    

    只需再增加一个条件,我们也可以支持反向范围 -

    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
    

    最后一个可以可视化为 -

    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]
    

    【讨论】:

      【解决方案2】:

      第二个代码块不起作用的原因是if (endNum = startNum) 行。通过使用单个等号,您将startNum 分配给endNum

      要检查是否相等,您可以使用 equality operator (==) 或 strict equality operator (===):

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

      【讨论】:

      • 是的,我刚刚意识到 :'(((。谢谢!
      【解决方案3】:

      问题是您使用的是赋值运算符而不是相等运算符。

      正确

      if (endNum === startNum)
      

      不正确

      if (endNum = startNum)
      

      【讨论】:

      • 我太笨了........非常感谢!
      • 我们都这样做。大声笑。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-27
      • 2017-07-11
      • 1970-01-01
      • 2017-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多