反向打印列表:TCL
我正在读Don Libes的“Expect探索:基于TCL的工具包…” 本章末尾的问题是“编写一个过程来反转字符串。如果您编写了一个迭代解决方案,现在就编写一个递归解决方案,反之亦然。” 读到目前为止,我决定尝试以下方法:反向打印列表:TCL,tcl,reverse,expect,Tcl,Reverse,Expect,我正在读Don Libes的“Expect探索:基于TCL的工具包…” 本章末尾的问题是“编写一个过程来反转字符串。如果您编写了一个迭代解决方案,现在就编写一个递归解决方案,反之亦然。” 读到目前为止,我决定尝试以下方法: set list {a b c d e f g} for {set index [expr [llength $list]-1]} {$index>=0} {incr $index - 1} { for {set i [expr [llength $list]-1
set list {a b c d e f g}
for {set index [expr [llength $list]-1]} {$index>=0} {incr $index - 1} {
for {set i [expr [llength $list]-1]} {$i>=0} {incr $i - 1} {
puts [lindex $list $index]
}
}
但我得到了以下错误:
Error(s), warning(s):
wrong # args: should be "incr varName ?increment?"
while executing
"incr $i - 1"
("for" body line 3)
invoked from within
"for {set index [expr [llength $list]-1]} {$index>=0} {incr $index - 1} {
for {set i [expr [llength $list]-1]} {$i>=0} {incr $i - 1} {
puts [lind..."
(file "source_file.tcl" line 4)
g
我发现我没有正确地证明“index”变量,尽管我不确定为什么。
此外,这种方法是递归的还是迭代的
如有任何建议,将不胜感激
________解决方案____________________________________ 根据@glenn提供的解决方案/方法,正确代码如下:
set list {a b c d e f g}
for {set i [expr {[llength $list]-1}]} {$i>=0} {incr i -1} {
puts [lindex $list $i]
}
他的文章下面展示了许多其他示例。首先,您要向incr传递3个参数:
$index
、-
和1
。如错误消息所示,incr最多接受2个参数。将“负1”指定为-1
,不带空格
请仔细注意错误消息:
wrong # args: should be "incr varName ?increment?"
注意它是如何显示的varName
——当您使用$index
时,您传递的是变量的值,而不是名称。删除$
for {set i [expr {[llength $list]-1}]} {$i>=0} {incr i -1} {
# .................................................. ^ ^^
# varname increment
请注意expr:的参数周围的大括号:这是一个好习惯。下面是
proc lreverse_rec {list} {
if {[llength $list] == 0} return
set procname [lindex [info level 0] 0]
return [concat [lindex $list end] [$procname [lrange $list 0 end-1]]]
}
proc lreverse_tail {list {result {}}} {
if {[llength $list] == 0} {return $result}
lappend result [lindex $list end]
set procname [lindex [info level 0] 0]
tailcall $procname [lrange $list 0 end-1] $result
}
proc lreverse_tail {list {result {}}} {
if {[llength $list] == 0} {return $result}
lappend result [lindex $list end]
set procname [lindex [info level 0] 0]
tailcall $procname [lrange $list 0 end-1] $result
}
proc lreverse_while_b {list} {
set result {}
while {[llength $list]} {
lappend result [lindex $list end]
set list [lrange $list[set list {}] 0 end-1]
}
return $result
}
proc pop {listVar} {
upvar 1 $listVar list
set result [lindex $list end]
set list [lrange $list[set list {}] 0 end-1]
return $result
}
proc push {listVar value} {
upvar 1 $listVar list
lappend list $value
}
proc shift {listVar} {
upvar 1 $listVar list
set result [lindex $list 0]
set list [lrange $list[set list {}] 1 end]
return $result
}
proc unshift {listVar value} {
upvar 1 $listVar list
set list [linsert $list[set list {}] 0 $value]
}
所有这些都导致了这个整洁的解决方案
proc lreverse_listops {list} {
set result {}
while {[llength $list]} {push result [pop list]}
return $result
}
set list[…$list[set list{}].]
习惯用法,但这是在变异值时对Tcl内部进行的优化。更新:在这里:(谢谢卡尔文先生)
还有一些基准测试
## put all the above procedures here ...
proc main {} {
set list [list]
for {set i 0} {$i <= 100} {incr i} {lappend list $i}
foreach proc {
lreverse_rec
lreverse_tail
lreverse_while_a
lreverse_while_b
lreverse_listops
} {
puts [format "%-20s %s" $proc [time [list $proc $list] 1000]]
}
}
main
为什么有2个for循环?FWIW,现在反转字符串是内置的:
string reverse
。类似地,反转列表是lreverse
。尽管如此,尝试用手做这件事还是一个很好的练习。谢谢你!!这帮了大忙。我现在将回顾你的第一篇文章。顺便说一句,我将代码修改为:set list{a b c d e f g}对于{set I[expr{[lleength$list]-1}{$I>=0}{incr I-1}{put[lindex$list$I]}
建议编写$list[set list{}
而不是$list[unset list]
。目标是相同的,但是使用set
比unset
更有效。请参见中的“取消共享对象”。
lreverse_rec 271.029 microseconds per iteration
lreverse_tail 293.496 microseconds per iteration
lreverse_while_a 75.541 microseconds per iteration
lreverse_while_b 53.962 microseconds per iteration
lreverse_listops 247.262 microseconds per iteration