如何在J语言中编写无循环的累加递归函数
J语言无循环实现阶乘基迭代收集
首先,针对你的需求,我们可以利用J语言的前缀扫描(\)和条件迭代特性,无需显式循环或累加器来实现目标。
核心逻辑梳理
你的函数f=:([<.@%]),(]|[)本质是输入(num, k),返回(num//k, num%k)(整数商和余数)。我们需要的迭代逻辑是:
- 初始输入为
(n, 1)(n是目标数,初始k=1) - 每次迭代用前一次的商作为新的num,同时k自增1,作为下一次输入
- 直到num变为0,收集所有余数并反转(得到你要的
3:4:1:0:1:0顺序)
问题2:传递迭代参数(无需显式循环)
先构造一个状态转换函数,用来生成下一次迭代的输入参数:
next_state=: ([: <.@% [ ]), (>: ])
这个函数接收二元组(num, k),返回(num//k, k+1)——也就是把前一次的商作为新num,k自增1,直接作为下一次的输入。
用J的**前缀扫描(\)**配合无限迭代^:_,可以自动生成所有迭代状态:
states=: next_state\^:_ 463 1
执行后会得到所有中间状态序列:
463 1 463 2 231 3 77 4 19 5 3 6 0 7 0 8 ...
我们只需要保留num>0的有效状态(到3 6为止),用筛选器过滤:
valid_states=: #~ 0&<.~ {. each states
这样就得到了所有需要参与余数计算的状态,完全不需要手动维护循环变量或累加器。
问题1:生成目标余数序列
从有效状态中提取每个(num, k)的余数(num%k),再反转顺序就能得到你要的序列:
remainders=: {: | {. each valid_states // 提取每个状态的余数 target_seq=: |. remainders // 反转得到最终序列
执行target_seq会输出:3 4 1 0 1 0,和你要的结果一致。
封装成完整函数
把上述步骤封装成一个可复用的动词,直接传入目标数即可:
factorial_base_digits=: 3 : 0 next_state=: ([: <.@% [ ]), (>: ]) states=: next_state\^:_ y , 1 valid_states=: #~ 0&<.~ {. each states |. {: | {. each valid_states )
测试调用:
factorial_base_digits 463
输出结果:3 4 1 0 1 0
关于windowing技术的说明
你提到的windowing技术,本质是通过序列的滑动窗口传递上下文参数。这里的前缀扫描\其实就是一种自动的windowing实现——它把每次迭代的结果作为下一次的输入窗口,自动完成参数的传递和推进,完美契合你的需求,无需手动处理窗口滑动逻辑。
内容的提问来源于stack exchange,提问作者Shmuel Greenberger
相关产品推荐
相关产品推荐

