使用JS中的递归函数计算数组元素个数

4

我正在学习《算法图解》这本书,试图理解递归。书中的一个挑战是“编写递归函数以计算列表中项的数量。” 我想出了以下代码,可以正常运行:

function recursiveArrayCount(arr, count) {
  if (arr.length == 0) {
    return 0;
  } else {
    arr.pop();
    return count + recursiveArrayCount(arr, count);
  }
}

let myArray = [1, 10, 23, 11, 4, 48, 88];
console.log(recursiveArrayCount(myArray, 1));

我的问题是,有没有更好的方法在 JavaScript 中实现这个功能?特别是我不喜欢必须使用初始值为“1”的计数器 - 但我想不到其他的方法。


2
“在JavaScript中有更好的方法吗?”:是的。这不是递归应该使用的东西。对于长数组,您将获得堆栈溢出错误。此外,您的函数正在使用pop改变数组。这对于调用者来说不好,他们会发现在调用之后他们的数组已被破坏。另外,看到尝试计算数组条目而不使用length属性(当然是直接的解决方案)的代码仍然使用该属性也很奇怪。 - trincot
我同意trincot在评论中所说的话。在一个应该计算数组长度但不使用length属性的函数中使用length属性是奇怪的。 - Yousaf
我同意在实践中你永远不会这样做,这只是为了理解递归而进行的练习。我也同意使用arr.length是一个糟糕的选择,考虑到函数的作用。将其更改为if(arr =='')可以正常工作并且更有意义。 - crims0n
2个回答

4
您根本不需要第二个参数:
function recursiveArrayCount(arr) {
    if (arr.length == 0) {
        return 0;
    }
    return 1 + recursiveArrayCount(arr.slice(1));
}

1
我也喜欢使用 slice 而不是修改原始数组。另一种方法是更改 if,它不需要复制数组 修改它:if (arr.length <= count) { return count; } - T.J. Crowder
谢谢!这正是我正在寻找的——简单而优美。 - crims0n
1
@T.J.Crowder 但是使用 arr.length 有点作弊... 如果我们可以直接访问 length 属性,就没有必要进行计数了... - Mulan
1
@Yousaf - 是的,但这是一个巨大的限制条件,这也是我的观点。 :-) - T.J. Crowder
如果您坚持不检查长度属性,您可以通过 arr.every(v => false) 来确定数组是否为空。 - Aplet123
显示剩余4条评论

0

通过消除在递归调用返回后仍需要的变量引用,使尾调用正确。

function recursiveArrayCount(arr) {
  return _recursiveCount(arr, 0);

  function _recursiveCount(arr, count) {
    return arr.length == 0 ? count : _recursiveCount(arr.slice(1), count + 1);
  }
}

let myArray = [1, 10, 23, 11, 4, 48, 88];
console.log(recursiveArrayCount(myArray));

这样做可以更有可能通过重用堆栈空间进行优化。

此外,我使用了嵌套函数来进行递归,这确保了count的正确初始化。


你也可以在内部函数中加入一些花哨的东西,像这样:

function recursiveArrayCount(arr) {
  return (function _recursiveCount(arr, count) {
    return arr.length == 0 ? count : _recursiveCount(arr.slice(1), count + 1);
  })(arr, 0);
}

let myArray = [1, 10, 23, 11, 4, 48, 88];
console.log(recursiveArrayCount(myArray));

这是一个递归调用的IIFE。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接