如何有效(mem/time)修改Tcl中列表的所有元素?

cfi*_*cfi 5 performance benchmarking list-comprehension tcl map

要对列表的每个元素进行操作,返回修改后的列表,各种语言都有明确的结构.

在Perl中有地图:

perl -e 'my @a = (1..4); print join(q( ), map { $_ * $_ } @a)'
1 4 9 16
Run Code Online (Sandbox Code Playgroud)

在Python中有列表推导:

>>> a = (1,2,3,4)
>>> [el*el for el in a]
[1, 4, 9, 16]
Run Code Online (Sandbox Code Playgroud)

在Tcl中执行此操作的最有效方法是什么?我可以想出通常的foreach循环.

set l {}
foreach i {1 2 3 4} {
    lappend l [expr $i * $i]
}
puts $l
1 4 9 16
Run Code Online (Sandbox Code Playgroud)

这是最快的方式吗?

关于mem效率,这将逐一建立第二个列表.如果我不需要永久列表是否有更有效的方法?

最后,还有更短的东西吗?我在这里或http://wiki.tcl.tk找不到信息

回答:

正如Donal Fellows已经回答的那样,最重要的是速度测试,事情应该包含在proc {}中,因为Tcl然后可以优化.对于Tcl,将讨论"映射"函数作为未来的增强.通过这个提示和进一步搜索,我找到了http://wiki.tcl.tk/12848

Don*_*ows 8

最有效的方法是:

set idx 0
foreach item $theList {
    lset theList $idx [expr {$item * $item}]
    incr idx
}
Run Code Online (Sandbox Code Playgroud)

如果列表很短(例如,几百个元素),则分配新列表的成本很小,因此您可以使用此(更简单)版本:

foreach item $theList {
    lappend newList [expr {$item * $item}]
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果将foreach命令放在过程(或lambda表达式或方法)中,则该命令只有快速,并且只有放在{大括号中才能快速生成表达式}.另外,不要推测,测量:注意使用time命令来查明代码的真实速度.

  • 将东西放入过程(或lambda)中的原因很重要,因为它提供了一个局部变量表.在内部,快速访问LVT.但是,当存在LVT时(即,在proc内),某些命令仅被编译为字节码.在大多数实际代码中都可以,因为几乎所有对性能至关重要的东西一直都放在程序中; 它只是在基准测试中,它实际上可能是一个问题.:-) (2认同)