反向打印清单:TCL

时间:2018-11-30 16:39:46

标签: tcl reverse expect

我正在阅读Don Libes撰写的“探索期望:基于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]} {$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]

}

他的帖子中还显示了许多其他示例。

2 个答案:

答案 0 :(得分:1)

首先,您要将3个参数传递给incr:enum { OUTSIDE_BSPH = 0, INSIDE_BSPH = 1 }; bool bsph = true; //... bsph = false; f(OUTSIDE_BSPH, arg1, arg2, arg3, arg4, arg5); if (bsph) { f(INSIDE_BSPH, arg1, arg2, arg3, arg4, arg5); } g(OUTSIDE_BSPH, arg6, arg7, arg8); if (bsph) { g(INSIDE_BSPH, arg6, arg7, arg8); } h(OUTSIDE_BSPH, arg3, arg4, arg5); if (bsph) { h(INSIDE_BSPH, arg3, arg4, arg5); } // ... caller(bsph, f, arg1, arg2, arg3, arg4, arg5); caller(bsph, g, arg6, arg7, arg8); caller(bsph, h, arg3, arg4, arg5); // ... <div id="google_translate_element"></div><script type="text/javascript"> function googleTranslateElementInit() { new google.translate.TranslateElement({pageLanguage: 'en', includedLanguages: 'es', layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element'); } </script><script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script> 。如错误消息所示,incr最多接受2个参数。将“负1”指定为$index,不带空格。

请注意错误消息:

-

请注意1的说法-使用-1时,您传递的是变量的 value 而不是 name 。删除wrong # args: should be "incr varName ?increment?"

varName

请注意expr参数周围的花括号:这是一个很好的习惯。

答案 1 :(得分:1)

以下是lreverse

的几种不同实现
  1. 递归

    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]]]
    }
    
  2. 尾递归

    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
    }
    
  3. while循环a(来自本主题的very old discussion

    proc lreverse_while_a {xlist} {
        set rlist $xlist
        for {
            set j 0
            set i [expr {[llength $xlist]-1}]
        } {$i>=0} {
            incr i -1
            incr j
        } {
            set rlist [lreplace $rlist[set rlist {}] $j $j [lindex $xlist $i]]
        }
        set rlist
    }
    
  4. while循环b

    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
    }
    
  5. while循环,但具有一些便利的list-op procs

    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内部的一种优化。更新:这里是:https://wiki.tcl-lang.org/page/K(感谢mrcalvin)


一些基准测试

## 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

输出类似

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