【发布时间】:2021-11-08 20:51:19
【问题描述】:
我目前正在尽可能多地学习递归,但我真的不知道如何使用它来检查数组中的所有数字元素是否都是偶数。使用 ES6,我可以使用 "every" 来实现如下期望的结果:
const isEven = (arr) => arr.every((item) => item % 2 === 0);
console.log(isEven([2,4,6,8])); // true
console.log(isEven([2,4,6,9])); // false
以下是我的递归尝试:
const isEven = (arr) => (arr.length === 0) ? true : isEven(arr.slice(1)) % 2 === 0;
console.log(isEven([2,4,6,8])); // true
console.log(isEven([2,4,6,9])); // true
如您所见,第二个示例的结果不正确,我感觉我也没有走在正确的道路上。有人可以告诉我我做错了什么吗?
【问题讨论】:
-
按照 ES6 的方式来做。这是递归的严重误用。如果您出于教学原因学习递归,那么选择它实际上有用的问题很重要,例如遍历二叉树,这会通过非线性因素分解问题。如果您真的必须这样做,请使用数组索引而不是切片。即使你修复了这个错误,这个算法也不必要地是 O(n*n)。
-
@ggorlen:我非常不同意。头尾列表是一种同样有效的递归结构,对于新手来说比树更简单。虽然 JS 本身不提供列表,但密集数组提供了它们的合理复制,使用
[0]和.slice(1),或者如果将它们具体化为head和tail或first和rest更好(请不要一直使用car和cdr!)是的,性能会很糟糕,但这不是学习练习的重点。 -
@ScottSauyet 是的,我们过去在这方面存在分歧。问题是新手并没有真正意识到您在生产 JS 中永远会做这种事情。他们被教导递归,就好像人们在 JS 中编写商业应用程序的方式一样。它不是。
arr.every更加地道。这比性能问题更糟糕:如果列表中包含的元素超过几千个微不足道的元素,那么它就会破坏堆栈。为什么像 Haskell 一样教 JS?用 Haskell 教 Haskell 范式,用 JS 教 JS 范式。否则人们只会感到非常困惑,正如我每天在recursion 标签中看到的那样。 -
留下这样的帖子没有评论递归打开的意外二次复杂性和安全漏洞对未来的访问者和可能试图除了未能引导学生批判性地思考他们被赋予的任务之外,在生产中使用这种根本上被破坏的代码。请提前原谅我,因为我每次看到都会留下这样的评论!
-
安全漏洞是导致应用程序崩溃的未捕获崩溃。如果学生们在这些帖子的开头写着“我意识到这是一种糟糕的做法,但我的教授让我这样做”,我会很好。但几乎从来没有这样。我对 CS 教育系统强迫学生左右用螺丝刀敲钉子而没有解释警告感到沮丧。递归实际上非常有用,所以如果他们可以简单地选择比任何替代方法都简单的问题,学生们会喜欢这个工具的。我不相信人为的例子。
标签: javascript recursion ecmascript-6