在JS中以递归方式向上和向下计数



我目前正在研究函数式编程技术。有关于这个问题的主题[特别是关于java],但没有关于JS的主题。

我想创建一个递归函数,它可以首先,从我指示的数字开始向上计数,直到我决定的极限,然后在达到极限时开始向下计数。我已经可以用for循环来做这件事了,但感觉像是硬编码的,因为我在循环中提供数字

基本上是这样的:

counter(0,10);
// 0, 1, 2, 3 ... 10, 9, 8... 0

以下是我的想法:

counter = (number, limit) => {
limit !=== 0
if ( number = limit ) {
counter(number -1, limit -1)
console.log(number)
} else if ( number < limit ) {
counter(number + 1, limit + 1)
}
}

这背后的想法是,如果数字低于极限计数,如果它们相等,则将每个参数递减1,以继续满足第一个if条件

当我在v8上运行此命令时,它会给出一个rangeError";达到最大堆栈大小">

此外,这不应该是一个无限循环。

对于循环版本:

for (let i = 0; i < 11; i++ ) { console.log(i) }
for (let i = 9; i < 11 && i > -1; i--) { console.log(i) }

递归是一种函数继承,因此将其与函数样式一起使用会产生最佳结果。这意味着要避免突变、变量重新分配和其他副作用。

  1. 如果开始a大于停止b,我们就达到了基本情况。返回空结果[]
  2. (电感)a小于或等于b。如果a等于b,则返回单例结果;峰值;山的[a]
  3. (电感)CCD_ 9小于CCD_ 10。重复子问题a + 1, b,并用a附加/预附加结果

这编码为一个纯函数表达式,下面的注释与上面的编号解释匹配-

const uppendown = (a, b) =>
a > b
? []                                // #1
: a == b
? [ a ]                             // #2
: [ a, ...uppendown(a + 1, b), a ]      // #3

const ex1 =
uppendown(0, 10)

const ex2 =
uppendown(3,7)
const ex3 =
uppendown(9,7)

console.log(JSON.stringify(ex1))
// [0,1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1,0]
console.log(JSON.stringify(ex2))
// [3,4,5,6,7,6,5,4,3]
console.log(JSON.stringify(ex3))
// []

uppenDown(3,7)
= [ 3, ...uppendDown(3 + 1, 7), 3 ]                   // #3
= [ 3, 4, ...uppendDown(4 + 1, 7), 4, 3 ]             // #3
= [ 3, 4, 5, ...uppendDown(5 + 1, 7), 5, 4, 3 ]       // #3
= [ 3, 4, 5, 6, ...uppendDown(6 + 1, 7), 6, 5, 4, 3 ] // #2
= [ 3, 4, 5, 6, 7, 6, 5, 4, 3 ]
uppendown(9,7)                        // #1
= []

如果出于某种任意原因,您不喜欢链接函数式三元表达式,您可以用它们交换命令式if语句-

function uppendown (a, b)
{ if (a > b)
return []                                // #1
else if (a == b)
return [ a ]                             // #2
else
return [ a, ...uppendown(a + 1, b), a ]  // #3
}

const ex1 =
uppendown(0, 10)

const ex2 =
uppendown(3,7)
const ex3 =
uppendown(9,7)

console.log(JSON.stringify(ex1))
// [0,1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1,0]
console.log(JSON.stringify(ex2))
// [3,4,5,6,7,6,5,4,3]
console.log(JSON.stringify(ex3))
// []


如果你想让数字一个接一个地出来,而不是返回一个数组,你可以使用JavaScript的生成器。注意每个程序变体之间惊人的相似性-

function* uppendown (a, b)
{ if (a > b)
return                                  // #1
else if (a == b)
yield a                                 // #2
else
( yield a                               // #3
, yield *uppendown(a + 1, b)            //
, yield a                               //
)
}

for (const x of uppendown(3, 7))
console.log(x)

// 3
// 4
// 5
// 6
// 7
// 6
// 5
// 4
// 3

您不需要向下循环或递减值,因为当您达到基本情况(停止递归的东西)时,您将跳回调用函数,该函数保存以前的value:

counter(0, 10) // logs: 0
|           ^
|           | (returns back to)
|---> counter(1, 10) // logs: 1
|             ^
|             | (returns back to)
|---> counter(2, 10) // logs: 2 <---
|                         | (returns back to)
|                         |
........   ---> counter(10, 10) // logs: 10 - base case

counter()的每次调用都将再次调用计数器(如上图所示,带有子counter调用),然后这些调用将打印其当前的value。当您到达基本情况时,您将打印当前值并返回,这将使您将控制权传递回调用函数。我的意思是,当你调用一个函数时,这个函数就会运行。当函数结束时,代码会从函数最初调用的位置返回:

function bar() {
console.log("bar");
}
console.log("foo"):
bar(); // call the function makes the code execution jump up into `bar` function. When that completes, our code execution jumps back to the next line, which logs "baz"
console.log("baz");

在我们的counter()示例中,调用子counter()函数的地方是它的父counter函数,当子函数完成执行(返回)时,我们将跳转(将控制传递回)它。一旦控制权被传递回来。对于调用函数(即上图中的父函数),您可以再次记录的value,因为它包含value:的前一个值

function counter(value, limit) {
if(value === limit) {
console.log(value);
} else {
console.log(value); // on the way down / going deeper (increment)
counter(value+1, limit);
console.log(value); // on the way up / coming up from the depths (decrement)
}
}
counter(0,10);
// 0, 1, 2, 3 ... 10, 9, 8... 0

类似的东西?

console.clear();
{
"use strict"

// Curry function
const nextStepInit = start => max => {
let increment = 1;
let counter = start;

return () => {
counter += increment;
if (counter >= max) {
increment = -increment;
return max;
}
if (counter <= start) {
return start;
}
return counter;
}
}

// this is a function, because nextStep(start)(max) returns a function
const nextStep = nextStepInit(0)(10)

const output = result => document.getElementById('output').value = result

const onClick = () => output(nextStep())

output(0)

document.getElementById('next-step').addEventListener('click', onClick)
}
<button id="next-step">Next Step</button><br>
<input id="output" disabled/>

相关内容

  • 没有找到相关文章

最新更新