繁体   English   中英

尝试学习递归,不太了解范围

[英]Trying to learn recursion, don't quite understand scope

 function isNumber(arr) { var result = []; if (arr.length > 1) { if (typeof arr[0] === 'number') { result.push(arr[0]); arr.splice(0, 1); isNumber(arr); } else { arr.splice(0, 1); isNumber(arr); } } else { console.log(result); } } isNumber([1,'2','3',2]); 

我正在尝试创建一个通过数组的函数,如果第一项是数字,它将删除它并将其推入名为result的数组。 然后,它再次调用自身,直到数组为空。

当前它返回一个空数组,调试器显示结果数组不断重置为空数组。

我知道为什么会发生这种情况,但我正在尝试找出解决方法。

要了解递归,您必须了解递归:)

  • 定义终端条件( array.length为0)
  • 定义步骤(您在当前步骤上的操作)如何更深入。

 function isNumber(arr) { // terminate recursion if (arr.length === 0) return [] // step var first = arr[0], rest = arr.slice(1) // if first is a number concat it with the rest else next step return typeof first === 'number'? [first].concat(isNumber(rest)) : isNumber(rest) } console.log(isNumber([1, '2', '3', 2])); 

结果应该在函数外部创建,因为现在每个函数调用都会创建一个新的空结果,并使用新的结果,而不是旧的结果,那么您可以将函数检查到其中

    var result = [];
    function isNumber(arr) {            
        if (arr.length > 1) {
            if (typeof arr[0] === 'number') {
                result.push(arr[0]);
                arr.splice(0, 1);
                isNumber(arr);
            } else {
                arr.splice(0, 1);
                isNumber(arr);
            }
        } else {
            console.log(result);
        }

    }

    isNumber([1,'2','3',2]);
    console.log(result);

如果需要,函数将返回带有结果的数组,则应将数组作为函数的参数传递,然后在函数调用后对其进行检查

    function isNumber(arr, result) {            
        if (arr.length > 1) {
            if (typeof arr[0] === 'number') {
                result.push(arr[0],result);
                arr.splice(0, 1);
                isNumber(arr);
            } else {
                arr.splice(0, 1);
                isNumber(arr,result);
            }
        } 

    }

  var result=[];
  isNumber([1,'2','3',2], result);

  console.log(result);

您需要存储结果并返回。

 function isNumber(arr) { var result = typeof arr[0] === 'number' ? [arr[0]] : []; arr.shift(); return arr.length ? result.concat(isNumber(arr)) : result; } console.log(isNumber([1, '2', '3', 2])); console.log(isNumber([])); 

您可以通过两种不同的方式来实现。 这需要随身携带结果数组,但可以进行尾调用优化:

function onlyNumbers(arr, result) {
  if (typeof result === "undefined") result = [];
  if (arr.length == 0) return result;
  let element = arr.shift();
  if (typeof element === "number") {
    result.push(element);
  }
  return onlyNumbers(arr, result);
}

我在这里使用一个技巧来仅在第一个调用中初始化结果数组。 在更严格的语言中,我将使用两个不同的函数:一个(非递归)仅用于使用(arr, [])调用另一个函数。 在第一个循环之后,结果数组随每个调用一起传递,并随每个递归调用一起填充,然后解开调用堆栈,并返回result而无需进行任何更改。

对于这种模式,情况恰恰相反(在概念上更简单,因为您不需要额外的参数,但无法很好地对其进行优化):

function onlyNumbers(arr) {
  if (arr.length == 0) return [];
  let element = arr.shift();
  let result = onlyNumbers(arr);
  if (typeof element === "number") {
    result.unshift(element);
  }
  return result;
}

在这里,我们不预先构造结果数组,而是在堆栈展开时将结果元素(向后!)附加到返回值上。

当然,递归是功能编程的基础。 在许多函数式编程语言中,没有其他方法可以循环,只有递归。 但这并不意味着递归仍然是原始操作:通常,这些语言将基于递归构建其他更复杂的操作,然后使用这些语言代替裸递归来产生很大的效果。 其中最基本的是mapfilterreduce

了解了递归代码的工作原理后,您可能希望了解如何通过递归来实现filter ,以及如何在JavaScript中使用更简单的单行代码:

[1,'2','3',2].filter(x => typeof x === "number")
# => [1, 2]

只需对代码进行最少的更改:

 function isNumber(arr, result) { if (arr.length > 0) { if (typeof arr[0] === 'number') { result.push(arr[0]); arr.splice(0, 1); return isNumber(arr, result); } else { arr.splice(0, 1); return isNumber(arr, result); } } else { console.log(result); } } isNumber([1,'2','3',2], []); 

为此,使用递归没有任何意义。 如果您真的想这样做,那么下面的示例就是一种方法。

每次调用函数将新变量存储在数组中时,都需要传递结果数组,以便可以在最后将其返回。 在您当前的示例中,它一直覆盖该变量。

 function isNumber(arr, res) { // If there is no res set, create a new array var result = res || []; // Base case, return the result if the arr is empty if (arr.length <= 0) { console.log(result); return result; } // Get the first element from the array (and remove it from the array) var firstElement = arr.shift(); // If it's a number, add it to the array if (typeof firstElement === 'number') { result.push(firstElement); } isNumber(arr, result); } isNumber([1, '2', '3', 2]); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM