使用递归的范围,如何输出新的数组Javascript

时间:2016-05-25 23:34:51

标签: javascript arrays recursion

如何在不声明函数外部的空数组的情况下使用递归输出新数组?另一种方法是创建一个内部函数然后return newFunction(),但不允许这样做,因为任务是调用函数本身。这就是我到目前为止所拥有的:

var newArr=[];
var range = function(x, y) {
    if(x === y-1){
        return newArr;
    }
    if(x < y){
        newArr.push(x+1);
        newArr = range(x+1,y);
    }
    else{
        newArr.push(x-1);
        newArr = range(x-1,y);
    }
    return newArr;
};
range(2,10) //[3,4,5,6,7,8,9]

4 个答案:

答案 0 :(得分:2)

因此,这种思考的关键是要理解你应该创建很多数组。

看一个稍微不同的例子......

阶乘是一个倒数的数字,通过正整数,将每个术语乘以低于它的术语,并写成5!。 当您发现自己提出如下问题时,这些很有帮助:
&#34;有多少____的排列?&#34;

&#34;鉴于这5件事,我可以从左到右安排多少次排列?&#34;

5! // =>
5 x 4 x 3 x 2 x 1  // =>
120

你可以看到我们如何构建循环并为计数器设置变量,为总计设置变量,并将当前总数乘以我们减少的计数器的当前值。

但是我们可以尝试使用递归而不是这样做。 首先,考虑如何将5 x 4 x ...简化为一个重复步骤。

实际上,2!2 x 13!3 x 2 x 1,恰好是3 x 2!

因此,一般情况可能类似于:n! == n x (n - 1)!

所以我可能会编写一个广义函数,它可以做这样的事情:

// DO NOT RUN THIS FUNCTION!
function factorial (n) {
  return n * factorial(n - 1);
}

因此,如果我运行factorial(5)并运用我的想象力,我们可以看到程序正在执行以下操作:

factorial(5)
  => return 5 * factorial(5-1)
    => return 4 * factorial(4-1)
      => return 3 * factorial(3-1)
        => ...

你能看到这个功能有什么问题吗?
我在开始时说过阶乘(在这个简化的情况下)是正整数。

当整数停止为正数时,我的函数如何知道停止? 目前还没有。这就是为什么上面的实现试图永远运行,并且会在它确实达到最大呼叫深度之前,冻结浏览器,同时尝试深入到成千上万或几万个函数。堆叠和爆炸。

我们真正需要的是一个条件或一组条件,我们用它来确定我们何时完成。 这是一个基础案例。

if (shouldStop(n)) {
  return defaultValue;
}

或者在我们的案例中:

function factorial (n) {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

现在,当我们运行该函数时,我们有:

factorial(5)
  => 5 * factorial(5 - 1)
    => 4 * factorial(4 - 1)
      => 3 * factorial(3 - 1)
        => 2 * factorial(2 - 1)
          => 1
        => 2 * 1
      => 3 * 2
    => 4 * 6
  => 5 * 24
=> 120

这是递归。 而且由于调用的位置(在你所在的任何分支的最末端返回)它是一种特殊的递归(尾递归),它允许某些语言优化代码,替换函数调用使用函数调用的内容,因此跳过像第一个版本一样添加到调用堆栈(JS的未来版本将支持此功能)。

在更现代的JS中,我可能会将其重写为类似

的内容
const factorial = n => n <= 1 ? 1 : factorial(n - 1);

现在,其他案例呢?

嗯,有时,你需要确保你传递更多的东西。 想想你的问题是什么,以及你需要什么类型的柜台或旗帜或收藏家,以便完成你的工作。

这是一个:

function makeNumberString (current, max, initialString) {
  var str = initialString || ""; // maybe I don't have one yet
  var currentString = str.concat(current.toString());

  if (current > max) {
    return initialString;
  }
  return makeNumberString(current + 1, max, currentString);
}

makeNumberString(0, 9); // "0123456789"

还有其他方法可以填充该功能,使其做同样的事情。 请注意currentString总是有一个全新的字符串,通过将我给出的字符串与我传递的新值相结合而制作。我实际上并没有修改原始字符串,而是创建了一个新副本[HINT !!]。

我希望能帮助你。

答案 1 :(得分:1)

你可以这样做;

var range = (x,y,a=[]) => (++x < y && (a = range(x,y,a.concat(x))),a),
      arr = range(2,10);
console.log(arr);

请注意,返回的数组是函数的参数,并传递给连续的递归调用。

答案 2 :(得分:0)

有很多方法可以给这只猫上皮。

  1. 简单的方法:创建一个包含第一个值的数组,然后 将剩余的值连接到它。
  2. &#13;
    &#13;
    var range = function(x,y){
        return x+1 >= y ? [] : [x+1].concat(range(x+1, y));
    }
    console.log(JSON.stringify(range(1, 10)));
    &#13;
    &#13;
    &#13;

    阵列是从右到左构建的。注意如何 递归调用range并不是函数的最后一件事 在它返回之前:数组的连接如下。

    1. 我们还可以使用累加器作为参数将函数重写为tail recursive
    2. &#13;
      &#13;
      var range2 = function(x,y,a){
          a = a || [];
          return x+1 >= y ? a : range2(x+1, y, a.concat(x+1));
      }
      console.log(JSON.stringify(range2(1, 10)));
      &#13;
      &#13;
      &#13;

      现在调用range2是该函数之前做的最后一件事 它返回。符合ES6标准的JS引擎required to optimise 通过丢弃执行来调用尾部位置(在严格模式下) 来自堆栈的上下文。

      注意我们现在如何从左到右构建数组。

      1. 您可以使用辅助函数来避免额外参数。 我已经使用了内部功能,但它并不是必须的。
      2. &#13;
        &#13;
        var range3 = function(x,y){
            var r = function(x,y,a){
                return x+1 >= y ? a : r(x+1, y, a.concat(x+1));
            }
            return r(x, y, []);
        }
        console.log(JSON.stringify(range3(1, 10)));
        &#13;
        &#13;
        &#13;

        1. 使用continuation passing style递归递归。
        2. &#13;
          &#13;
          var range4 = function(x,y){
              var r = function(x,y,c){
                  return x+1 >= y ? c([]) : r(x+1, y, function(a){
                      return c([x+1].concat(a));
                  });
              }
              return r(x, y, function(a){return a;});
          }
          console.log(JSON.stringify(range4(1, 10)));
          &#13;
          &#13;
          &#13;

          注意与原始range的相似性:数组是 反向构建。这对你来说更加棘手 可能是你永远不需要的东西,但要注意它并没有什么坏处 它

答案 3 :(得分:0)

试试这个:

function rangeRecursive(start, end) {            
    if(start === end){
        return end;
    } else if(start > end){
        return [];
    } else {
        return [start].concat(rangeRecursive(++start, end));
    } 
}

console.log(rangeRecursive(4, 15));