如何在不声明函数外部的空数组的情况下使用递归输出新数组?另一种方法是创建一个内部函数然后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]
答案 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 1
。 3!
为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)
有很多方法可以给这只猫上皮。
var range = function(x,y){
return x+1 >= y ? [] : [x+1].concat(range(x+1, y));
}
console.log(JSON.stringify(range(1, 10)));
&#13;
阵列是从右到左构建的。注意如何
递归调用range
并不是函数的最后一件事
在它返回之前:数组的连接如下。
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;
现在调用range2
是该函数之前做的最后一件事
它返回。符合ES6标准的JS引擎required to
optimise
通过丢弃执行来调用尾部位置(在严格模式下)
来自堆栈的上下文。
注意我们现在如何从左到右构建数组。
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;
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;
注意与原始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));