Javascript 跟踪递归函数被调用的次数
Javascript 跟踪递归函数被调用的次数,javascript,recursion,Javascript,Recursion,函数单位数(num){ 设计数器=0 让number=[…num+'').map(number).reduce((x,y)=>{return x*y}) 如果(number您应该在函数定义中添加一个反参数: 函数单位数(num,计数器=0){ log(`called${counter}times`) //... 返回单位数(数字,计数器+1) } 一位数(39) 您可以为此使用闭包 只需将计数器存储到函数的闭包中即可 下面是一个例子: 函数singleDigitDecorator(){ 设计数
函数单位数(num){
设计数器=0
让number=[…num+'').map(number).reduce((x,y)=>{return x*y})
如果(number您应该在函数定义中添加一个反参数:
函数单位数(num,计数器=0){
log(`called${counter}times`)
//...
返回单位数(数字,计数器+1)
}
一位数(39)
您可以为此使用闭包
只需将计数器
存储到函数的闭包中即可
下面是一个例子:
函数singleDigitDecorator(){
设计数器=0;
返回函数singleDigitWork(num,isCalledRecursive){
//如果使用新参数调用,则重置
如果(!粗略调用){
计数器=0;
}
计数器+++;//*
log(`called${counter}times`);
让number=[…(num+“”).映射(number).减少((x,y)=>{
返回x*y;
});
if(number传统的解决方案是将计数作为参数传递给另一个答案所建议的函数
然而,js中还有另一个解决方案。其他一些答案建议只在递归函数之外声明count:
let counter = 0
function singleDigit(num) {
counter++;
// ..
}
这当然有效。但是这会使函数不可重入(不能正确调用两次)。在某些情况下,您可以忽略此问题,只需确保不调用两次singleDigit
(javascript是单线程的,因此不太难实现)但是,如果您稍后将个位数
更新为异步,这将是一个等待发生的错误,而且感觉很难看
解决方案是在外部而不是全局声明计数器变量。这是可能的,因为javascript有闭包:
function singleDigit(num) {
let counter = 0; // outside but in a closure
// use an inner function as the real recursive function:
function recursion (num) {
counter ++
let number = [...num + ''].map(Number).reduce((x, y) => {return x * y})
if(number <= 9){
return counter // return final count (terminate)
}else{
return recursion(number) // recurse!
}
}
return recursion(num); // start recursion
}
函数单位数(num){
let counter=0;//外部但在闭包中
//使用内部函数作为实际递归函数:
函数递归(num){
柜台++
让number=[…num+'').map(number).reduce((x,y)=>{return x*y})
如果(number另一种方法是使用生成器,因为您生成了所有的数字
最后一个元素是数字n
减少为一个位数,要计算迭代次数,只需读取数组的长度即可
const digits=[…到单个数字(39)];
控制台日志(数字);
//=>[27,14,4]
函数*到单个数字(n){
做{
n=[…字符串(n)].reduce((x,y)=>x*y);
产氮量;
}而(n>9);
}
如果你只是想计算它减少了多少次,而不是特别关心递归…你可以删除递归。下面的代码仍然忠实于原始帖子,因为它不计算num,这里有很多有趣的答案。我想我的版本提供了一个额外的有趣的答案另类
您可以对所需的函数执行几项操作。您可以递归地将其减少到一位数。您可以记录中间值,并需要进行递归调用的计数。处理所有这些操作的一种方法是编写一个纯函数,该函数将返回一个数据结构,其中包含最终结果、所采取的步骤和调用计数ll in one:
{
数字:4,
步骤:[39、27、14、4],
电话:3
}
然后,如果需要,您可以记录这些步骤,或者存储它们以供进一步处理
这里有一个版本可以做到这一点:
const singledigital=(n,steps=[])=>
n a*b),[…步骤,n])
log(单位数(39))
这几乎是一个纯学术的变体,但您可以使用
让我们稍微缩短和改进您的原始功能:
function singleDigit(n) {
let digitProduct = [...(n + '')].reduce((x, y) => x * y, 1);
return digitProduct <= 9 ? digitProduct : singleDigit(digitProduct);
}
// singleDigit(123234234) == 0
其中我们有Ynormal(singleDigitF,123234234)==0
现在是诀窍。既然我们已经分解了Y组合子的递归,我们可以计算其中的递归数:
function Ycount(f, ...args) {
let count = 1;
let Y = (g) => g(() => {count += 1; return Y(g);});
return [Y(f)(...args), count];
}
节点REPL中的快速检查提供:
> Ycount(singleDigitF, 123234234)
[ 0, 3 ]
> let digitProduct = (n) => [...(n + '')].reduce((x, y) => x * y, 1)
undefined
> digitProduct(123234234)
3456
> digitProduct(3456)
360
> digitProduct(360)
0
> Ycount(singleDigitF, 39)
[ 4, 3 ]
这个组合器现在可以计算以singleDigitF
风格编写的任何递归函数中的调用数
(请注意,将零作为一个非常常见的答案有两个来源:数字溢出(12334545699999999
变成12334545700000000
等),以及当输入的大小增加时,几乎肯定会在某个地方将零作为中间值。)这是一个Python版本,它使用包装函数简化计数器,正如slebetman的回答所建议的那样-我写这篇文章只是因为在这个实现中核心思想非常清楚:
from functools import reduce
def single_digit(n: int) -> tuple:
"""Take an integer >= 0 and return a tuple of the single-digit product reduction
and the number of reductions performed."""
def _single_digit(n, i):
if n <= 9:
return n, i
else:
digits = (int(d) for d in str(n))
product = reduce(lambda x, y: x * y, digits)
return _single_digit(product, i + 1)
return _single_digit(n, 0)
>>> single_digit(39)
(4, 3)
从functools导入reduce
def单位数字(n:int)->元组:
“”“获取一个大于等于0的整数,并返回一个单位数乘积的元组。”
以及执行的减少次数
def单位数字(n,i):
如果n>>单个数字(39)
(4, 3)
为什么不在函数中调用
编辑:要在浏览器中尝试的代码段:
函数单位数(num){
控制台。计数(“单位数”);
设计数器=0
让number=[…num+'').map(number).reduce((x,y)=>{return x*y})
如果(数字太棒了。看起来我的计数器不工作了,因为我在function@chs242作用域规则规定,在函数中声明它将在每次调用时创建一个新的。@chs242不是在函数中声明它。从技术上讲,所有默认参数也都在这样做——在您的情况下,它只是该值从未结转到下一次递归调用函数时。a.e.每次函数运行时计数器
都会被废弃并设置为0
,除非您像Sheraff那样在递归调用中明确地结转它。a.e.单位数(数字,++计数器)
right@zfrisch我现在明白了。感谢您花时间解释。请将++counter
更改为counter+1
。它们在功能上是平等的
function Ynormal(f, ...args) {
let Y = (g) => g(() => Y(g));
return Y(f)(...args);
}
function Ycount(f, ...args) {
let count = 1;
let Y = (g) => g(() => {count += 1; return Y(g);});
return [Y(f)(...args), count];
}
> Ycount(singleDigitF, 123234234)
[ 0, 3 ]
> let digitProduct = (n) => [...(n + '')].reduce((x, y) => x * y, 1)
undefined
> digitProduct(123234234)
3456
> digitProduct(3456)
360
> digitProduct(360)
0
> Ycount(singleDigitF, 39)
[ 4, 3 ]
from functools import reduce
def single_digit(n: int) -> tuple:
"""Take an integer >= 0 and return a tuple of the single-digit product reduction
and the number of reductions performed."""
def _single_digit(n, i):
if n <= 9:
return n, i
else:
digits = (int(d) for d in str(n))
product = reduce(lambda x, y: x * y, digits)
return _single_digit(product, i + 1)
return _single_digit(n, 0)
>>> single_digit(39)
(4, 3)