find()的递归版本

时间:2017-09-22 18:31:25

标签: javascript recursion find

我想做的是创建一个递归版本的find,它接受一个数组和一个测试函数,并返回一个数组的第一个元素,它通过了测试。让我们看一下这个例子:

function isEven(num) { return(num%2 == 0); }
var arr = [1, 3, 5, 4, 2];

function findRecursive(arr, func) {
    var p = arr.shift();
    if (func(p) == true)
        return p;
    else 
        findRecursive(arr, func);
}

findRecursive(arr, isEven);

由于某种原因,我得到了不确定。但是如果我在第5行改变为弹出,它会正确返回2.导致这个问题的原因是什么?

2 个答案:

答案 0 :(得分:2)

您需要返回递归调用的值,否则返回{J}中函数的标准return value undefined

} else {
    return findRecursive(arr, func);
    // ^^^
}

如果没有要检查的元素,您可以插入对数组长度的检查。然后你可以故意返回undefined



function isEven(num) { return num % 2 === 0; }

function findRight(array, fn) {
    if (!array.length) {
        return;
    }

    var p = array.pop();
    return fn(p) ? p : findRight(array, fn);
}

console.log(findRight([1, 3, 5, 4, 2], isEven)); // 2
console.log(findRight([1, 3, 5], isEven));       // undefined




答案 1 :(得分:1)

递归是一种在函数式编程环境中诞生的循环机制;从它的上下文中取出它只能粗略地理解如何使用递归

递归,当与其他函数式编程实践(如持久性(不可变)数据类型和纯函数)一起使用时,可以作为纯表达式精美地表达

const find = (f, [x,...xs]) =>
  x === undefined
    ? x
    : f (x)
      ? x
      : find (f, xs)

const isEven = x =>
  (x & 1) === 0
      
console.log (find (isEven, [1, 3, 5, 4, 2])) // 4
console.log (find (isEven, [1, 3, 5, 7, 9])) // undefined

Be careful with recursion in JavaScript, tho - 使用堆栈安全循环机制来避免在大型阵列上吹掉堆栈

const recur = (...values) =>
  ({ type: recur, values })
  
const loop = f =>
  {
    let acc = f ()
    while (acc && acc.type === recur)
      acc = f (...acc.values)
    return acc
  }
  
const find = (f, xs) =>
  loop ((i = 0) =>
    i === xs.length
      ? undefined
      : f (xs [i])
        ? xs [i]
        : recur (i + 1))

const isEven = x =>
  (x & 1) === 0

// [ 1, 2, 3, 4, ... 20000 ]
const numbers =
  Array.from (Array (2e4), (x,n) => n + 1)
  
console.log (find (isEven, numbers))     // 2

// this would have blown the stack using the first version of `find`
// but it works just fine here, thanks to loop/recur
console.log (find (x => x < 0, numbers)) // undefined