我找到了一个关于如何计算列表深度的维基页面: http://wiki.tcl.tk/11602
如何使用tcl 8.6功能 lmap 和应用将上述代码重写为单一过程?也许真的不需要“申请”。
proc max list {
set res [lindex $list 0]
foreach e [lrange $list 1 end] {if {$e>$res} {set res $e}}
set res
}
# llmap perhaps can be replaced with lmap from Tcl 8.6
proc llmap {func list} {
set res {}
foreach e $list {lappend res [$func $e]}
set res
}
proc ldepth list {
expr {
[llength $list] == 0? 1:
[expr {[lindex $list 0] eq $list}]? 0:
1+[max [llmap ldepth $list]]
}
}
答案 0 :(得分:5)
第一级改编已经让我们接近你想去的地方,足以让我认为这是我的生产解决方案:
proc ldepth {list} {
expr {
[llength $list] == 0 ? 1 :
[lindex $list 0] eq $list ? 0 :
1 + [tcl::mathfunc::max {*}[lmap e $list {
ldepth $e
}]]
}
}
这使用标准lmap
和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]
}
}
通过使用工作队列来完全无递归。这是8.5代码 - 不需要8.6功能 - 您可以通过替换lassign
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功能对一切都没有意义。
答案 1 :(得分:0)
这是一个简单的可行方法。 它只会整理列表,直到无法再整理为止。尝试次数是深度。无需递归。
proc ldepth {lst} {
set depth 1
set fatter $lst
set flatter [join $fatter]
while {$flatter ne $fatter} {
set fatter $flatter
set flatter [join $fatter]
incr depth
}
return depth
}
希望这会有所帮助!