【问题标题】:What does "return a" in this recursive combinations function does?这个递归组合函数中的“return a”是做什么的?
【发布时间】:2020-02-15 19:15:45
【问题描述】:

我在 Chrome 调试器中一遍又一遍地检查了这个函数,但仍然无法理解 return a 的作用。感谢您帮助我!

这里有一些说明: 我明白第一轮。使用以下参数调用匿名函数:

活动 = "", 休息 = "abc", a = []

然后它调用自己直到rest 为空,当它填充a 数组时:

活动 = "abc", 休息 = "", a = ["abc"]

此时我们到达return a,调试器跳转到else 语句中的第二个fn 调用,而不是第一个if 语句。参数已经如下所示:

活动 = "ab", 休息 = "c", a = ["abc"]

这是我完全不明白的部分。我知道递归只有在activerest 为空时才结束,但在return a 之后,即使在调试器中都没有检查 if 语句,它只是突出显示了提到的第二个函数调用,此时“ c" 已分配给rest。我猜这个函数不产生重复的原因也在这里,但如果不是,那可能是另一个问题。无论如何,再次感谢您的帮助!

combinations("abc");

function combinations(str) {
    var fn = function(active, rest, a) {
        if (!active && !rest)
            return;
        if (!rest) {
            a.push(active);
        } else {
            fn(active + rest[0], rest.slice(1), a);
            fn(active, rest.slice(1), a);
        }
        return a;
    }
    return fn("", str, []);
}

【问题讨论】:

  • 它从递归中返回,这意味着在return 之后它将到达调用它的行。接下来是第二行,进行第二次调用。
  • 函数的布局很奇怪..也就是说,返回应该总是“return;” (或者更好的是,两个返回都消除了!)并且辅助函数应该返回变异对象本身。然后是“return a;”最后更明显是多余的。
  • 按照上面的“return a;”仅用于偷运出变异对象(假设终端情况不是立即为真),并且本身与递归无关。
  • @user2864740 感谢您的回答,我现在明白了!但主要的是(因为我不小心删除了我之前的评论)第一次调用的参数被传递给第二次调用。
  • @Premierplan 如果明确指定,是的:) 这是由fn(.., .., a) 完成的,例如,与退货无关。

标签: javascript recursion permutation


【解决方案1】:

在这种情况下,递归构造写得很奇怪,“return a”只是将变异数组(最初提供的相同对象)偷运回辅助函数,以便可以在内部递归上使用直接返回函数调用。 (在大多数情况下,and especially those discussed in recursion primers,递归函数通常使用返回值。)

这里是一个更清洁的使用辅助函数重写的方法。我还删除了所有显式返回语句,因为它们没有在这里增加价值。

function combinations(str) {
    var fn = function(active, rest, a) {
        if (!active && !rest) {
            // base case #1 - implicit return, no recursive call
        } else if (!rest) {
            // base case #2 - implicit return, no recursive call
            a.push(active);
        } else {
            // recursive case, where function is called again
            // (the object "a" is modified in recursion;
            //  result of recursion not directly used)
            fn(active + rest[0], rest.slice(1), a);
            fn(active, rest.slice(1), a);
        }
    }

    var o = [];     // only one output object created..
    fn("", str, o); // ..mutated..
    return o;       // ..and returned to caller.
}

然后应该很容易观察到不需要将“a”传递给递归函数(即它可以访问封闭范围内的“o”),因为在初始之后没有分配给“a”的新对象结果数组已创建。

重写将(更正确地)为空输入字符串返回一个空数组存在细微差别。

【讨论】:

    【解决方案2】:

    虽然我知道这个问题主要是关于特定递归实现的工作原理(并且已经有一个很好的答案!),但我认为值得指出的是它是一个奇怪的实现,像这样的东西可能更干净:

    const combinations = (str, active = '') => 
      str .length == 0
        ? active .length == 0
          ? []
          : [active]
        : [
            ... combinations (str .slice (1), active + str [0]),
            ... combinations (str .slice (1), active)
          ]
    
    console .log (combinations ('abc'))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-26
      • 2017-07-07
      • 2022-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多