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

时间:2017-09-07 09:27:31

标签: javascript arrays recursion



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的数组。然后它再次调用自己,直到数组为空。

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

我理解为什么会发生这种情况,但我想弄清楚如何解决这个问题。

6 个答案:

答案 0 :(得分:2)

要理解递归,你必须理解递归:)

  • 定义终端条件(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]));




答案 1 :(得分:1)

结果应该在函数外部创建,因为现在每个函数调用都会创建一个新的空结果并使用新的结果,而不是旧结果,那么你可以检查函数是否正常工作

    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);

答案 2 :(得分:1)

您需要存储结果并将其返回。

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([]));

答案 3 :(得分:1)

你可以用两种不同的方式做到这一点。这个需要随身携带结果数组,但可以进行尾调用优化:

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]

答案 4 :(得分:1)

对代码进行最少的更改:



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], []);




答案 5 :(得分:0)

对此事使用递归没有任何意义。如果你真的想这样做,那么下面的例子是一种方法。

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



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]);
&#13;
&#13;
&#13;