第一级适应已经让我们接近你想要去的地方,足以让这就是我认为的生产解决方案:
proc ldepth {list} {
expr {
[llength $list] == 0 ? 1 :
[lindex $list 0] eq $list ? 0 :
1 + [tcl::mathfunc::max {*}[lmap e $list {
ldepth $e
}]]
}
}
这使用了标准lmap
and tcl::mathfunc::max
(这是max()
函数的实现)。请注意,扩展 和tcl::mathfunc::max
是 Tcl 8.5的功能,但它们在这里非常有用。
消除膨胀
tcl::mathfunc::max
让我们看看我们是否可以通过扩展摆脱这个调用。
proc ldepth {list} {
set m -inf
expr {
[llength $list] == 0 ? 1 :
[lindex $list 0] eq $list ? 0 :
1 + [lindex [lmap e $list {
set m [expr { max($m, [ldepth $e]) }]
}] end]
}
}
嗯,就是有点丑。我们不妨这样做:
proc ldepth {list} {
set m -inf
expr {
[llength $list] == 0 ? 1 :
[lindex $list 0] eq $list ? 0 :
[foreach e $list {
set m [expr { max($m,[ldepth $e]) }]
}
expr {$m + 1}]
}
}
这肯定不会变得更好,除了它没有保持那么多状态(只是一个运行最大值,而不是深度列表)。让我们回到那个版本lmap
!(真正的美丽真正需要的是lfold
,但这并没有完成,因为有时您必须停止添加功能并调用发布。)
“消除”递归
我们可以采取的另一种方法是查看删除外部递归。我们不能完全消除递归——我们正在处理递归结构上的递归操作——但我们不需要把它放在rename ldepth fred
会导致问题的外层。我们通过使用apply
创建一个类似内部过程的东西来做到这一点,并且由于我们正在进行递归调用,我们将 lambda 项传递给自身。(您可以采取一些技巧来获得该值而无需明确传递它,但它们很丑陋,我们不妨在这里诚实。)
proc ldepth {list} {
set ldepth {{ldepth list} {expr {
[llength $list] == 0 ? 1 :
[lindex $list 0] eq $list ? 0 :
1 + [tcl::mathfunc::max {*}[lmap e $list {
apply $ldepth $ldepth $e
}]]
}}
apply $ldepth $ldepth $list
}
全字节码版本
受制于仍在进行递归调用。
proc ldepth {list} {
expr {
[llength $list] == 0 ? [return 1] :
[lindex $list 0] eq $list ? [return 0] :
[set m -inf
foreach e $list {
set m [expr {[set d [ldepth $e]]+1>$m ? $d+1 : $m}]
}
return $m]
}
}
通过使用工作队列来完全无递归。lassign
这是 8.5 的代码——不需要 8.6 的特性——你可以通过替换s将其写成适合 8.4 :
proc ldepth {list} {
set work [list $list 0]
set maxdepth 0
while {[llength $work]} {
### 8.4 version
# foreach {list depth} $work break
# set work [lrange $work 2 end]
set work [lassign $work[unset -nocomplain work] list depth]
if {[llength $list] == 0} {
incr depth
} elseif {[lindex $list 0] ne $list} {
incr depth
foreach e $list {
lappend work $e $depth
}
continue
}
set maxdepth [expr {$maxdepth<$depth ? $depth : $maxdepth}]
}
return $maxdepth
}
这个故事的主旨?8.6 的功能对所有东西都没有意义。