我试图教自己如何编写递归函数,有人建议尝试将循环转换为递归。所以我试图将第一个for循环函数更改为递归函数。这是我的代码:
// Function that uses for loop.
function onlyOne(value1, value2, value3) {
var array = [value1, value2, value3];
var count = 0;
for(var i = 0; i < array.length; i++) {
if(!!array[i] === true) {
count ++;
}
} if(count === 1) {
return true;
} else {
return false;
}
}
// Function that uses recursion.
function onlyOne2(a, b, c) {
var array = [a, b, c];
var count = 0;
var numTrue = 0;
if(!!array[count] === true) {
numTrue++;
}
if(count === array.length-1) {
if(numTrue === 1) {
return true;
} else {
return false;
}
}else {
count++;
return onlyOne2(a, b, c);
}
}
console.log(onlyOne2(true, false, false));
如果只有一个参数是真实的,那么每个函数的目的是返回true。否则该函数返回false。 for循环功能正常工作。但是,当我使用递归函数时,我得到错误:超出了最大调用堆栈大小。我想知道我做错了什么。谢谢你的帮助!
答案 0 :(得分:1)
if(!!array[i] === true)
直接使用布尔值:if(array[i])
您要求true
值返回true
if (count === 1) { // <- Use this comparison to return the specific value.
return true;
^
} else {
return false;
^
}
直接返回比较:return count === 1;
在函数onlyOne2
中,停止循环的“递归情况”不正确。
count === array.length-1
^ ^
您必须使用索引i
// Function that uses for loop.
function onlyOne(value1, value2, value3) {
var array = [value1, value2, value3];
var count = 0;
for (var i = 0; i < array.length; i++) {
if (array[i]) {
count++;
}
}
return count === 1;
}
console.log(onlyOne(true, false, false));
function onlyOne2(value1, value2, value3, count, i) {
var array = [value1, value2, value3];
if (i === array.length) return count === 1;
if (array[i]) count++;
return onlyOne2(value1, value2, value3, count, ++i);
}
console.log(onlyOne2(true, false, false, 0, 0));
请参阅?现在正在使用递归来处理循环。
答案 1 :(得分:1)
您可以为需要的truthy值和rest parameters ...
计算递归函数的计数器。
它适用于tail recursion和任意数量的参数。
function only(count, v, ...rest) {
if (v) { // check value
if (!count) { // check count is zero
return false; // because found more truthy than needed
}
count--; // decrement count
}
if (!rest.length) { // check length is zero
return !count; // return not count
}
return only(count, ...rest); // tail call with count and rest
}
console.log(only(1, false, false, false)); // false
console.log(only(1, false, false, true)); // true
console.log(only(1, false, true, false)); // true
console.log(only(1, false, true, true)); // false
console.log(only(1, true, false, false)); // true
console.log(only(1, true, false, true)); // false
console.log(only(1, true, true, false)); // false
console.log(only(1, true, true, true)); // false
console.log('-----');
console.log(only(2, false, false, false)); // false
console.log(only(2, false, false, true)); // false
console.log(only(2, false, true, false)); // false
console.log(only(2, false, true, true)); // true
console.log(only(2, true, false, false)); // false
console.log(only(2, true, false, true)); // true
console.log(only(2, true, true, false)); // true
console.log(only(2, true, true, true)); // false
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
答案 2 :(得分:0)
上面代码的问题是每次函数递归count
和numTrue
时再次声明,因此发生无限循环,这是正确的代码(声明count
和{ {1}}全球:
numTrue
答案 3 :(得分:0)
这很有趣。好的,所以我们有一个函数,如果数组中的其中一个项目是真的,则返回true。让我们考虑一下递归的基本要求。
基本情况,数组为空:
if (!array.length)
return false;
基本情况,数组中只有一个元素:
if (array.length == 1)
return !!array[0] === true
否则:
let next = f(rest-of-array)
if (!!array[0] === true)
return !next
else
return next
JavaScript代码:
function f(arr, i){
// Same as !array.length
if (i == arr.length)
return false;
// Same as array.length == 1
if (i == arr.length - 1)
return !!arr[i]
// Same as f(rest-of-array)
let next = f(arr, i + 1)
if (!!arr[i])
return !next
return next
}
输出:
f([undefined,2,0], 0)
=> true
f([1,2,undefined], 0)
=> false
f([undefined,false,1], 0)
=> true
f([5,false,false], 0)
=> true
答案 4 :(得分:0)
您可以将任何for
循环转换为递归:
let a=0, b=1,
for (let n=5; n > 0; n--) {
const tmpa = a;
a = b;
b += tmpa;
}
此处a
。 b
和n
更改,原因是具有第6个斐波纳契数的a
值。所以我们将它们作为参数并返回:
function forLoop(n, a, b) {
if(n > 0) {
return forLoop(n - 1, b, a + b);
}
return a;
}
const a = forLoop(5, 0, 1);
因此对于使用for
循环的函数
function onlyOne(value1, value2, value3) {
const array = [value1, value2, value3];
let count = 0;
for(var i = 0; i < array.length; i++) {
if(!!array[i] === true) {
count ++;
}
}
if(count === 1) {
return true;
}
return false;
}
您要更改的绑定是count
和i
:
function onlyOne(value1, value2, value3) {
function iterate(count, i) {
if (i < array.length) {
if (!!array[i] === true) {
return iterate(count + 1, i + 1);
}
return iterate(count, i + 1);
}
return count;
}
const array = [value1, value2, value3];
const count = iterate(0, 0);
if(count === 1) {
return true;
}
return false;
}
由于你只有3个元素,这可能已经足够好但想象你想为数组实现这样的事情,你应该计划尽可能快地返回。在for
版本中,它看起来像这样:
function onlyOne(arr) {
let count = 0;
const len = array.length; // cache
for (index = 0; index < len; index++) {
if (arr[index]) {
count++;
if(count > 1) return false; // early return
}
}
return count === 1;
}
与递归相同:
function onlyOne(arr) {
function iterate (index, count) {
if (index < len && count <= 1) {
return iterate(
index + 1,
count + (array[index] ? 1 : 0)
);
}
return count;
}
const len = array.length; // cache
const count = iterate(0, 0);
return count === 1;
}
注意它并不完全相同,因为我们期望迭代计数,return
只返回被调用者。因此,这里的早期返回只是不迭代更多的值,但我们仍然返回一个作为最终结果主题的计数。您可以使用for
代替break
在return
中执行相同操作。
同样适用于any
/ some
,它应该返回第一个true和all
,它应该为第一个false值返回false。当它无法改变答案时,迭代每个元素都没有意义。
答案 5 :(得分:0)
你不妨试试这个。你不需要改变你的函数结构或任何东西,它可以使用任意数量的参数。
function onlyOne(a,b,c){
let arr = Array.from(arguments);
let count = 0;
let item = arr.shift();
if(true === item){
++count;
}
if(arr.length > 0) {
count += onlyOne.apply(this,arr);
return count == 1;
}
return count;
}
答案 6 :(得分:0)
我建议从一个更简单的例子开始:
function logRecurse(i, arr) {
if (i < arr.length) {
console.log(arr[i]);
logRecurse(i+1, arr);
}
}
var array = [false, false, true, false];
logRecurse(0, array);
然后添加return语句:
function truthyRecurse(i, arr) {
if (i < arr.length) {
if (arr[i]) { // could be just: return arr[i] || truthyRecurse(...)
return true;
} else {
return truthyRecurse(i+1, arr);
}
}
return false;
}
var array = [false, false, true, false];
console.log(truthyRecurse(0, array));
但递归的真正用处在于目录结构。下一步吧!您可以将数组放入数组中来模拟它:
function logFiles(dir) {
// log filename (typeof string) or recurse into dir
}
var dir = [
"file1",
"file2",
[ // sub dir
"subfile1",
[ // sub-sub dir
"sub-subfile1",
"sub-subfile2",
"sub-subfile3",
],
"subfile2",
]
];
logFiles(dir);
答案 7 :(得分:0)
这是另一种解决方法 - 我最近写了另一个答案,旨在帮助学习者使用递归来实现高级思维。这里使用的技术是详细写的。如果您有兴趣,可以read it here。
const None =
Symbol ()
const loop = ([ x = None, ...xs ], foundTruthy = false) =>
x === None
? foundTruthy
: Boolean (x)
? foundTruthy
? false
: loop (xs, true)
: loop (xs, foundTruthy)
const onlyOne = (...xs) =>
loop (xs, false)
console.log
( onlyOne () // false
, onlyOne (0) // false
, onlyOne (1) // true
, onlyOne (0, '', false, 1) // true
, onlyOne (0, 0, 0, true, 1) // false
)
注意loop
可以是通用的,以便onlyOne
不需要依赖专门的助手 - mind the stack overflow
const None =
Symbol ()
const always = x => _ =>
x
const recur = (...values) =>
({ recur, values })
const loop = (f = always (null) , acc = f ()) =>
acc && acc.recur === recur
? loop (f, f (...acc.values))
: acc
const onlyOne = (...list) =>
loop (([ x = None, ...xs ] = list, foundTruthy = false) =>
x === None
? foundTruthy
: Boolean (x)
? foundTruthy
? false
: recur (xs, true)
: recur (xs, foundTruthy))
console.log
( onlyOne () // false
, onlyOne (0) // false
, onlyOne (1) // true
, onlyOne (0, '', false, 1) // true
, onlyOne (0, 0, 0, true, 1) // false
)
Nina的答案是函数参数如何降低程序复杂性的一个很好的例子 - 这个改编显示了如何用函数表达式编写相同的程序
const None =
Symbol ()
const only = (count = 1, x = None, ...xs) =>
x === None
? count === 0
: Boolean (x)
? only (count - 1, ...xs)
: only (count, ...xs)
console.log
( only () // false
, '---'
, only (0) // true
, only (0, false) // true
, only (0, true) // false
, '---'
, only (1) // false
, only (1, false) // false
, only (1, false, true) // true
, only (1, false, true, true) // false
, '---'
, only (2, false, true) // false
, only (2, false, true, true) // true
, only (2, false, true, true, true) // false
)
答案 8 :(得分:0)
你以错误的方式解决这个问题。您正在尝试将整个函数转换为递归函数。相反,正如所建议的那样,您只需要将循环转换为递归函数:
我试图教自己如何编写递归函数,有人建议尝试将循环转换为递归。
所以,让我们先看看你原来的功能。我为你清理了一下:
sticky
&#13;
请注意,我注释了循环的状态和循环变量。这些将是我们的递归函数的参数。我们将使用状态的初始值和循环变量作为输入调用递归函数来替换assert("Test 1", onlyOne(false, 0, "") === false);
assert("Test 2", onlyOne(false, 0, "x") === true);
assert("Test 3", onlyOne(false, 1, "") === true);
assert("Test 4", onlyOne(false, 1, "x") === false);
assert("Test 5", onlyOne(true, 0, "") === true);
assert("Test 6", onlyOne(true, 0, "x") === false);
assert("Test 7", onlyOne(true, 1, "") === false);
assert("Test 8", onlyOne(true, 1, "x") === false);
function onlyOne(a, b, c) {
const array = [a, b, c];
// +-- state of the loop
// | +-- initial value of the state
// | |
// v v
var count = 0;
// +-- loop variant
// | +-- initial value of the loop variant
// | |
// v v
for (let i = 0; i < 3; i++)
if (array[i]) count++;
return count === 1;
}
function assert(test, condition) {
console.log(test, condition ? "passed" : "failed");
}
循环。递归函数的结果将是循环的最终状态:
for
&#13;
希望您现在知道如何将任何循环转换为递归函数。